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..a16eb6aa6b04a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -49,6 +49,7 @@ "msbuild", "-p:RunAnalyzersDuringBuild=false", "-p:GenerateFullPaths=true", + "-tl:off", "src/Compilers/CSharp/csc/AnyCpu/csc.csproj" ], "problemMatcher": "$msCompile", @@ -62,6 +63,7 @@ "build", "-p:RunAnalyzersDuringBuild=false", "-p:GenerateFullPaths=true", + "-tl:off", "Compilers.slnf" ], "problemMatcher": "$msCompile", @@ -75,6 +77,7 @@ "build", "-p:RunAnalyzersDuringBuild=false", "-p:GenerateFullPaths=true", + "-tl:off", "Roslyn.sln" ], "problemMatcher": "$msCompile", @@ -145,7 +148,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..cad48a4dc4438 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: '' + - name: sha + type: string + default: '' + variables: - name: XUNIT_LOGS value: $(Build.SourcesDirectory)\artifacts\log\$(_configuration) @@ -33,8 +41,22 @@ variables: value: true stages: +- ${{ if ne(parameters.prNumber, '') }}: + - 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, '') }}: + - 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-official.yml b/azure-pipelines-official.yml index 4ff514dfeec51..981528e441d68 100644 --- a/azure-pipelines-official.yml +++ b/azure-pipelines-official.yml @@ -37,6 +37,18 @@ parameters: type: boolean default: true +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 + # The variables `_DotNetArtifactsCategory` and `_DotNetValidationArtifactsCategory` are required for proper publishing of build artifacts. See https://github.com/dotnet/roslyn/pull/38259 variables: - name: _DotNetArtifactsCategory @@ -53,6 +65,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 +91,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: @@ -339,6 +356,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/docs/Language Feature Status.md b/docs/Language Feature Status.md index 0981e775649e0..4037d257257a6 100644 --- a/docs/Language Feature Status.md +++ b/docs/Language Feature Status.md @@ -10,12 +10,10 @@ 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 @@ -30,6 +28,7 @@ efforts behind them. | [`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) | | [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](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# 12.0 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/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..43df945a6417a 100644 --- a/eng/Directory.Packages.props +++ b/eng/Directory.Packages.props @@ -5,7 +5,7 @@ 8.0.0-preview.23468.1 1.1.3-beta1.24319.1 0.1.187-beta - <_BasicReferenceAssembliesVersion>1.7.2 + <_BasicReferenceAssembliesVersion>1.7.8 4.8.0-3.final 17.10.191 @@ -111,8 +111,8 @@ - - + + @@ -121,7 +121,7 @@ - + @@ -144,7 +144,7 @@ - + + @@ -255,14 +255,11 @@ - - - @@ -290,13 +287,17 @@ + + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 49e3252e73c0a..c384a1ae5cb66 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -2,15 +2,15 @@ - + https://github.com/dotnet/source-build-externals - 311ef7fef52828f4a70a94d13e32c394fd3292ee + ee22054b44ec9615dc3481c4decc1b007a83a2b0 - + https://github.com/dotnet/source-build-reference-packages - 0b53e839fa2f09a5994cc6006533dcc3d45a4226 + c818c3cf018e7aa9fd31f6aed5d14e9b59f03e4f @@ -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..43472e1a059d4 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -8,7 +8,7 @@ 4 12 0 - 1 + 3 $(MajorVersion).$(MinorVersion).$(PatchVersion) 8.0.0 - 8.0.0 + 8.0.4 8.0.0 8.0.0 8.0.0 @@ -59,7 +59,7 @@ 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 @@ -83,5 +83,7 @@ --> true true + + true diff --git a/eng/build.ps1 b/eng/build.ps1 index edbcc77f9ec0e..c8d54142a6e71 100644 --- a/eng/build.ps1 +++ b/eng/build.ps1 @@ -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/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/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/config/PublishData.json b/eng/config/PublishData.json index bdff2ce9f662e..79d444bd6f09e 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,6 +206,16 @@ "vsMajorVersion": 17, "insertionTitlePrefix": "[d17.11]" }, + "release/dev17.12": { + "nugetKind": [ + "Shipping", + "NonShipping" + ], + "vsBranch": "rel/d17.12", + "vsMajorVersion": 17, + "insertionCreateDraftPR": false, + "insertionTitlePrefix": "[d17.12 P2]" + }, "main": { "nugetKind": [ "Shipping", @@ -223,7 +224,7 @@ "vsBranch": "main", "vsMajorVersion": 17, "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[d17.12 P1]" + "insertionTitlePrefix": "[d17.12 P3]" }, "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/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.targets b/eng/targets/Imports.targets index 46eb0380702c3..ba2a9ac4f8433 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 @@ + + + + + - + - - - - + + + + + + - - - - - - + - + + + + + + + - - - - - - - - - + + <_SkipUpgradeNetAnalyzersNuGetWarning>true - - false - $(CoreCompileDependsOn);ResolveKeySource 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/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/UseCollectionExpression/CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer.cs index 887b530668f8c..eacc1e33f9758 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UseCollectionExpression; -using static SyntaxFactory; +using static UseCollectionExpressionHelpers; [DiagnosticAnalyzer(LanguageNames.CSharp)] internal sealed partial class CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer() @@ -49,7 +49,8 @@ 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; @@ -59,6 +60,7 @@ private void AnalyzeArrayCreationExpression(SyntaxNodeAnalysisContext context, I public static ImmutableArray> TryGetMatches( SemanticModel semanticModel, ArrayCreationExpressionSyntax expression, + CollectionExpressionSyntax replacementExpression, INamedTypeSymbol? expressionType, bool allowSemanticsChange, CancellationToken cancellationToken, @@ -69,6 +71,7 @@ public static ImmutableArray> TryGetM var matches = UseCollectionExpressionHelpers.TryGetMatches( semanticModel, expression, + replacementExpression, expressionType, isSingletonInstance: false, allowSemanticsChange, @@ -79,8 +82,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 +104,7 @@ public static ImmutableArray> TryGetM if (ienumerableType is null) return default; - if (!UseCollectionExpressionHelpers.IsConstructibleCollectionType( + if (!IsConstructibleCollectionType( semanticModel.Compilation, ienumerableType.TypeArguments.Single())) { return default; @@ -114,6 +117,7 @@ public static ImmutableArray> TryGetM public static ImmutableArray> TryGetMatches( SemanticModel semanticModel, ImplicitArrayCreationExpressionSyntax expression, + CollectionExpressionSyntax replacementExpression, INamedTypeSymbol? expressionType, bool allowSemanticsChange, CancellationToken cancellationToken, @@ -121,8 +125,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 +158,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 +173,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/CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer.cs index dc8fc2a87fc37..607899dd00c26 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer.cs @@ -12,6 +12,8 @@ namespace Microsoft.CodeAnalysis.CSharp.UseCollectionExpression; +using static UseCollectionExpressionHelpers; + [DiagnosticAnalyzer(LanguageNames.CSharp)] internal sealed partial class CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer : AbstractCSharpUseCollectionExpressionDiagnosticAnalyzer @@ -127,6 +129,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/UseCollectionExpressionHelpers.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/UseCollectionExpressionHelpers.cs index 15d93e2106889..bedba7efb662a 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/UseCollectionExpressionHelpers.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/UseCollectionExpressionHelpers.cs @@ -33,11 +33,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 +151,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; @@ -805,6 +817,7 @@ private static bool ShouldReplaceExistingExpressionEntirely( public static ImmutableArray> TryGetMatches( SemanticModel semanticModel, TArrayCreationExpressionSyntax expression, + CollectionExpressionSyntax replacementExpression, INamedTypeSymbol? expressionType, bool isSingletonInstance, bool allowSemanticsChange, @@ -914,7 +927,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 +1235,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/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..106b78d3d4ca1 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, @@ -238,7 +239,7 @@ private static SyntaxNode ReplaceIdentifierWithInlineDeclaration( } public static TypeSyntax GenerateTypeSyntaxOrVar( - ITypeSymbol symbol, CSharpCodeFixOptionsProvider options) + ITypeSymbol symbol, CSharpSimplifierOptions options) { var useVar = IsVarDesired(symbol, options); @@ -251,7 +252,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..c5f2083c7c2a7 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpCollectionExpressionRewriter.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpCollectionExpressionRewriter.cs @@ -46,12 +46,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; diff --git a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForArrayCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForArrayCodeFixProvider.cs index 6131ccff3191a..3ca81464e419a 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForArrayCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForArrayCodeFixProvider.cs @@ -103,11 +103,11 @@ ImmutableArray> GetMatches( { 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/CSharpUseCollectionExpressionForFluentCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForFluentCodeFixProvider.cs index e6d5670884c6b..09314809aa588 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; @@ -144,11 +145,8 @@ static async Task> GetArgumentsAsync( 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..da987b48b87d4 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; 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..43978f21d34d9 100644 --- a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems +++ b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems @@ -33,7 +33,18 @@ + + + + + + + + + + + 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 100% rename from src/Features/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs rename to src/Analyzers/CSharp/Tests/ImplementAbstractClass/ImplementAbstractClassTests.cs 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 cf28711a00bfa..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)] @@ -8476,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(); } @@ -8515,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(); } @@ -8564,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(); } @@ -8618,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(); } @@ -8664,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(); } @@ -8712,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(); } @@ -8777,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(); } @@ -8823,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(); } @@ -8904,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(); } @@ -8943,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(); } @@ -9002,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(); } @@ -9058,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(); } @@ -9114,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(); } @@ -9614,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(); } @@ -9670,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(); } @@ -9726,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(); } @@ -9807,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(); } @@ -9846,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(); } @@ -9936,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(); } @@ -9979,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(); } @@ -10017,7 +10043,7 @@ public async Task TestWithNullableProperty() { await TestInRegularAndScriptAsync( """ - #nullable enable + #nullable enable public interface ITest { @@ -10028,7 +10054,7 @@ public class Test : {|CS0535:ITest|} } """, """ - #nullable enable + #nullable enable public interface ITest { @@ -10046,7 +10072,7 @@ public async Task TestWithNullablePropertyAlreadyImplemented() { var code = """ - #nullable enable + #nullable enable public interface ITest { @@ -10065,7 +10091,7 @@ public async Task TestWithNullableMethod() { await TestInRegularAndScriptAsync( """ - #nullable enable + #nullable enable public interface ITest { @@ -10076,7 +10102,7 @@ public class Test : {|CS0535:ITest|} } """, """ - #nullable enable + #nullable enable public interface ITest { @@ -10099,7 +10125,7 @@ public async Task TestWithNullableEvent() // see https://github.com/dotnet/roslyn/issues/36673 await TestInRegularAndScriptAsync( """ - #nullable enable + #nullable enable using System; @@ -10112,7 +10138,7 @@ public class Test : {|CS0535:ITest|} } """, """ - #nullable enable + #nullable enable using System; @@ -10132,7 +10158,7 @@ public async Task TestWithNullableDisabled() { await TestInRegularAndScriptAsync( """ - #nullable enable + #nullable enable public interface ITest { @@ -10146,7 +10172,7 @@ public class Test : {|CS0535:ITest|} } """, """ - #nullable enable + #nullable enable public interface ITest { @@ -10169,7 +10195,7 @@ public async Task GenericInterfaceNotNull1() { ReferenceAssemblies = ReferenceAssemblies.Net.Net50, TestCode = """ - #nullable enable + #nullable enable using System.Diagnostics.CodeAnalysis; @@ -10187,7 +10213,7 @@ class A : {|CS0535:{|CS0535:IFoo|}|} } """, FixedCode = """ - #nullable enable + #nullable enable using System.Diagnostics.CodeAnalysis; @@ -10289,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] @@ -10415,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")] @@ -10859,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")] @@ -10895,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")] @@ -10975,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(); } @@ -11012,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(); } @@ -11049,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(); } @@ -11084,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(); } @@ -11119,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(); } @@ -11161,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(); } @@ -11196,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(); } @@ -11231,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(); } @@ -11266,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(); @@ -11302,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(); @@ -11338,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(); @@ -11374,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(); @@ -11410,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(); @@ -11446,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(); @@ -11523,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(); } @@ -11599,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(); } @@ -11675,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(); } @@ -11817,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/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/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/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/Core/Analyzers/Analyzers.projitems b/src/Analyzers/Core/Analyzers/Analyzers.projitems index 845981b50d1b3..bc9457e004538 100644 --- a/src/Analyzers/Core/Analyzers/Analyzers.projitems +++ b/src/Analyzers/Core/Analyzers/Analyzers.projitems @@ -33,8 +33,6 @@ - - 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/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/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/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs index 34f7e41e03429..203f9d8ac17b4 100644 --- a/src/Analyzers/Core/Analyzers/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs @@ -136,6 +136,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 => @@ -236,11 +241,6 @@ private void AnalyzePropertyDeclaration( 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) - return; - var preferAutoProps = context.GetAnalyzerOptions().PreferAutoProperties; if (!preferAutoProps.Value) return; 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/xlf/AnalyzersResources.cs.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf index 783b82502cec7..4e9d5e4bc1703 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 + Base classes contain inaccessible unimplemented members + + 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 + Implement abstract class + + + + Implement through '{0}' + Implement through '{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..9aab7ea52155d 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 + Base classes contain inaccessible unimplemented members + + 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 + Implement abstract class + + + + Implement through '{0}' + Implement through '{0}' + + 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..980c2ac06750d 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 + Base classes contain inaccessible unimplemented members + + 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 + Implement abstract class + + + + Implement through '{0}' + Implement through '{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..1cf1460fe34bb 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 + Base classes contain inaccessible unimplemented members + + 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 + Implement abstract class + + + + Implement through '{0}' + Implement through '{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..6a995a06a8700 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 + Base classes contain inaccessible unimplemented members + + 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 + Implement abstract class + + + + Implement through '{0}' + Implement through '{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..e9ab67f02392d 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 + Base classes contain inaccessible unimplemented members + + Blank line required between block and subsequent statement ブロックと後続のステートメントの間に空白行が必要です @@ -147,6 +152,16 @@ 'GetHashCode' の実装を簡素化できます + + Implement abstract class + Implement abstract class + + + + Implement through '{0}' + Implement through '{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..736cf4bcd2356 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 + Base classes contain inaccessible unimplemented members + + Blank line required between block and subsequent statement 블록과 후속 문 사이에 빈 줄이 필요함 @@ -146,6 +151,16 @@ 'GetHashCode' 구현을 단순화할 수 있습니다. + + Implement abstract class + Implement abstract class + + + + Implement through '{0}' + Implement through '{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..7d2881ef2938c 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 + Base classes contain inaccessible unimplemented members + + 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 + Implement abstract class + + + + Implement through '{0}' + Implement through '{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..efbd9b9f71ba1 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 + Base classes contain inaccessible unimplemented members + + 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 + Implement abstract class + + + + Implement through '{0}' + Implement through '{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..f7a626dc6dddb 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 + Base classes contain inaccessible unimplemented members + + Blank line required between block and subsequent statement Необходима пустая линия между блоком и следующим оператором. @@ -146,6 +151,16 @@ Реализацию GetHashCode можно упростить. + + Implement abstract class + Implement abstract class + + + + Implement through '{0}' + Implement through '{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..12b748d385da3 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 + Base classes contain inaccessible unimplemented members + + 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 + Implement abstract class + + + + Implement through '{0}' + Implement through '{0}' + + 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..dee55b2cb9077 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 + Base classes contain inaccessible unimplemented members + + Blank line required between block and subsequent statement 块与后续语句之间需要有空白行 @@ -146,6 +151,16 @@ 可简化 "GetHashCode" 实现 + + Implement abstract class + Implement abstract class + + + + Implement through '{0}' + Implement through '{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..1bb2545ebe4d5 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 + Base classes contain inaccessible unimplemented members + + Blank line required between block and subsequent statement 區塊與後續陳述式之間必須有空白行 @@ -146,6 +151,16 @@ 'GetHashCode' 實作可簡化 + + Implement abstract class + Implement abstract class + + + + Implement through '{0}' + Implement through '{0}' + + Interpolation can be simplified 可簡化內插補點 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..2464b17f06d9e 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,6 +21,12 @@ 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 @@ -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 100% rename from src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs 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 89% rename from src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs index 48cf055fa3c7f..06f1f851076b8 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateEnumMember; @@ -22,7 +23,7 @@ private partial class GenerateEnumMemberCodeAction(Document document, State stat 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 100% rename from src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs 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 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateConversionService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateConversionService.State.cs 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 97% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs index adefeff36e7b1..980e1980c24eb 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs @@ -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 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs 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 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs similarity index 94% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs index 24dc35aa27167..2ab87259b4019 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs @@ -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 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.MethodSignatureInfo.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.MethodSignatureInfo.cs 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 94% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs index 59fa09abb2e3b..3356e6913fb69 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; @@ -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 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/TypeParameterSubstitution.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/TypeParameterSubstitution.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs similarity index 94% rename from src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs index 4c5a8e168bf49..40c1f1795eef3 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs @@ -15,6 +15,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.GenerateMember.GenerateVariable; internal abstract partial class AbstractGenerateVariableService @@ -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 97% rename from src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs index 27009e75e9acf..1cd52ccd264cc 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs @@ -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 92% rename from src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs index ab8cff038de7f..22463a0abd335 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs @@ -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 100% rename from src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.State.cs 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 91% rename from src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs rename to src/Analyzers/Core/CodeFixes/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs index b96844c5298ff..89b813f459da6 100644 --- a/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs @@ -48,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); @@ -62,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); @@ -70,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 95% rename from src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs rename to src/Analyzers/Core/CodeFixes/ImplementAbstractClass/ImplementAbstractClassData.cs index 6b43c78079bc4..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( @@ -95,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( @@ -172,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); @@ -200,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) @@ -232,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), @@ -246,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 92% rename from src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs index 8a0f328e31f6f..b78a2f7910461 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs @@ -75,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; } } @@ -104,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 @@ -118,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 94% rename from src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs index e64a3ec8df477..157a8ff24dacc 100644 --- a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs @@ -9,6 +9,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; internal abstract partial class AbstractImplementInterfaceService 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 91% rename from src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Method.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Method.cs index 7cca6268057b1..6c41d141632f7 100644 --- a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Method.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Method.cs @@ -7,6 +7,12 @@ 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 diff --git a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Property.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Property.cs similarity index 96% rename from src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Property.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Property.cs index 48e915de06709..eb20761ff1eda 100644 --- a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Property.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Property.cs @@ -13,6 +13,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; internal abstract partial class AbstractImplementInterfaceService @@ -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/Features/Core/Portable/ImplementType/ImplementTypeInsertionBehavior.cs b/src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypeInsertionBehavior.cs similarity index 100% rename from src/Features/Core/Portable/ImplementType/ImplementTypeInsertionBehavior.cs rename to src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypeInsertionBehavior.cs diff --git a/src/Features/Core/Portable/ImplementType/ImplementTypeOptions.cs b/src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypeOptions.cs similarity index 98% rename from src/Features/Core/Portable/ImplementType/ImplementTypeOptions.cs rename to src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypeOptions.cs index c4d01765cdfde..035ecd08f73a8 100644 --- a/src/Features/Core/Portable/ImplementType/ImplementTypeOptions.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypeOptions.cs @@ -2,14 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Immutable; -using System.Diagnostics; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.ImplementType; diff --git a/src/Features/Core/Portable/ImplementType/ImplementTypePropertyGenerationBehavior.cs b/src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypePropertyGenerationBehavior.cs similarity index 100% rename from src/Features/Core/Portable/ImplementType/ImplementTypePropertyGenerationBehavior.cs rename to src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypePropertyGenerationBehavior.cs 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/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/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/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/xlf/CodeFixesResources.cs.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf index 33815baba51e3..45e3c49828341 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf @@ -19,7 +19,7 @@ Add explicit cast - Přidat explicitní přetypování + Přidat explicitní přetypování @@ -62,6 +62,11 @@ Převést typ na {0} + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in Opravit všechny výskyty v @@ -72,6 +77,156 @@ Opravit porušení názvu: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + 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: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to 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..9f83900115ece 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf @@ -19,7 +19,7 @@ Add explicit cast - Explizite Umwandlung hinzufügen + Explizite Umwandlung hinzufügen @@ -62,6 +62,11 @@ Typ in "{0}" konvertieren + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in Alle Vorkommen korrigieren in @@ -72,6 +77,156 @@ Namensverletzung beheben: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + Make class 'abstract' Klasse als "abstract" festlegen @@ -122,6 +277,26 @@ Issues unterdrücken oder konfigurieren + + TODO: dispose managed state (managed objects) + TODO: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to null + + 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..193368b66ad71 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf @@ -19,7 +19,7 @@ Add explicit cast - Agregar conversión explícita + Agregar conversión explícita @@ -62,6 +62,11 @@ Convertir tipo en "{0}" + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in Corregir todas las repeticiones de @@ -72,6 +77,156 @@ Corregir infracción de nombre: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + Make class 'abstract' Convertir la clase en "abstract" @@ -122,6 +277,26 @@ Suprimir o configurar incidencias + + TODO: dispose managed state (managed objects) + TODO: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to 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..e3f51e039601d 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf @@ -19,7 +19,7 @@ Add explicit cast - Ajouter un cast explicite + Ajouter un cast explicite @@ -62,6 +62,11 @@ Convertir le type en '{0}' + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in Corriger toutes les occurrences dans @@ -72,6 +77,156 @@ Corrigez la violation de nom : {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + Make class 'abstract' Rendre la classe 'abstract' @@ -122,6 +277,26 @@ Supprimer ou configurer des problèmes + + TODO: dispose managed state (managed objects) + TODO: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to 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..31090b372b9c0 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf @@ -19,7 +19,7 @@ Add explicit cast - Aggiungi cast esplicito + Aggiungi cast esplicito @@ -62,6 +62,11 @@ Converti il tipo in '{0}' + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in Correggi tutte le occorrenze in @@ -72,6 +77,156 @@ Correggi violazione del nome: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + Make class 'abstract' Rendi la classe 'abstract' @@ -122,6 +277,26 @@ Elimina o configura i problemi + + TODO: dispose managed state (managed objects) + TODO: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to 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..68bf2e60a939d 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf @@ -19,7 +19,7 @@ Add explicit cast - 明示的なキャストの追加 + 明示的なキャストの追加 @@ -62,6 +62,11 @@ 型を '{0}' に変換 + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in 次の場所のすべての出現箇所を修正します @@ -72,6 +77,156 @@ 名前の違反を修正します: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + Make class 'abstract' クラスを 'abstract' にしてください @@ -122,6 +277,26 @@ 問題の抑制または構成 + + TODO: dispose managed state (managed objects) + TODO: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to 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..9512b178f9f51 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf @@ -19,7 +19,7 @@ Add explicit cast - 명시적 캐스트 추가 + 명시적 캐스트 추가 @@ -62,6 +62,11 @@ 형식을 '{0}'(으)로 변환 + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in 다음 위치에서 모든 발생 수정 @@ -72,6 +77,156 @@ 이름 위반 수정: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + Make class 'abstract' 'abstract' 클래스 만들기 @@ -122,6 +277,26 @@ 문제 표시 안 함 또는 구성 + + TODO: dispose managed state (managed objects) + TODO: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to 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..2dfb6a43e4c5f 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf @@ -19,7 +19,7 @@ Add explicit cast - Dodaj rzutowanie jawne + Dodaj rzutowanie jawne @@ -62,6 +62,11 @@ Konwertuj typ na „{0}” + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in Popraw wszystkie wystąpienia w @@ -72,6 +77,156 @@ Rozwiąż problem z naruszeniem nazwy: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + Make class 'abstract' Ustaw specyfikator „abstract” dla klasy @@ -122,6 +277,26 @@ Problemy z pomijaniem lub konfigurowaniem + + TODO: dispose managed state (managed objects) + TODO: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to null + + 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..493978f373bf6 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf @@ -19,7 +19,7 @@ Add explicit cast - Adicionar conversão explícita + Adicionar conversão explícita @@ -62,6 +62,11 @@ Converter o tipo em '{0}' + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in Corrigir todas as ocorrências em @@ -72,6 +77,156 @@ Corrigir violação de nome: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + Make class 'abstract' Tornar a classe 'abstract' @@ -122,6 +277,26 @@ Suprimir ou configurar problemas + + TODO: dispose managed state (managed objects) + TODO: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to null + + 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..10a02bfa8ca26 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf @@ -19,7 +19,7 @@ Add explicit cast - Добавить явное приведение + Добавить явное приведение @@ -62,6 +62,11 @@ Преобразовать тип в "{0}" + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in Исправить все случаи в @@ -72,6 +77,156 @@ Устраните нарушение имени: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + Make class 'abstract' Сделать класс абстрактным @@ -122,6 +277,26 @@ Подавление проблем или настройка уровня их серьезности + + TODO: dispose managed state (managed objects) + TODO: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to 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..a2c15d1babdf4 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf @@ -19,7 +19,7 @@ Add explicit cast - Açık tür dönüştürme ekle + Açık tür dönüştürme ekle @@ -62,6 +62,11 @@ Türü '{0}' olarak dönüştür + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in Tüm oluşumları şurada düzelt: @@ -72,6 +77,156 @@ Ad ihlalini düzelt: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + 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: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to null + + 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..d616b72a519a3 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf @@ -19,7 +19,7 @@ Add explicit cast - 添加显式转换 + 添加显式转换 @@ -62,6 +62,11 @@ 将类型转换为“{0}” + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in 修复以下对象中的所有实例: @@ -72,6 +77,156 @@ 解决名称冲突: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + Make class 'abstract' 将类设置为 "abstract" @@ -122,6 +277,26 @@ 抑制或配置方面的问题 + + TODO: dispose managed state (managed objects) + TODO: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to 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..00b98d172bfc4 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf @@ -19,7 +19,7 @@ Add explicit cast - 新增明確轉換 + 新增明確轉換 @@ -62,6 +62,11 @@ 將類型轉換為 '{0}' + + Do not change this code. Put cleanup code in '{0}' method + Do not change this code. Put cleanup code in '{0}' method + + Fix all occurrences in 修正所有出現之處於 @@ -72,6 +77,156 @@ 修正名稱違規: {0} + + Generate abstract method '{0}' + Generate abstract method '{0}' + + + + Generate abstract property '{0}' + Generate abstract property '{0}' + + + + Generate all + Generate all + + + + Generate constant '{0}' + Generate constant '{0}' + + + + Generate constructor '{0}({1})' + Generate constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generate constructor in '{0}' + + + + Generate constructor in '{0}' (with fields) + Generate constructor in '{0}' (with fields) + + + + Generate constructor in '{0}' (with properties) + Generate constructor in '{0}' (with properties) + + + + Generate enum member '{0}' + Generate enum member '{0}' + + + + Generate explicit conversion operator in '{0}' + Generate explicit conversion operator in '{0}' + + + + Generate field '{0}' + Generate field '{0}' + + + + Generate field assigning constructor '{0}({1})' + Generate field assigning constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generate implicit conversion operator in '{0}' + + + + Generate local '{0}' + Generate local '{0}' + + + + Generate method '{0}' + Generate method '{0}' + + + + Generate narrowing conversion in '{0}' + Generate narrowing conversion in '{0}' + + + + Generate parameter '{0}' + Generate parameter '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generate parameter '{0}' (and overrides/implementations) + + + + Generate property '{0}' + Generate property '{0}' + + + + Generate read-only field '{0}' + Generate read-only field '{0}' + + + + Generate read-only property '{0}' + Generate read-only property '{0}' + + + + Generate variable '{0}' + Generate variable '{0}' + + + + Generate widening conversion in '{0}' + Generate widening conversion in '{0}' + + + + Implement all members explicitly + Implement all members explicitly + + + + Implement interface + Implement interface + + + + Implement interface abstractly + Implement interface abstractly + + + + Implement interface explicitly with Dispose pattern + Implement interface explicitly with Dispose pattern + + + + Implement interface through '{0}' + Implement interface through '{0}' + + + + Implement interface with Dispose pattern + Implement interface with Dispose pattern + + + + Implement remaining members explicitly + Implement remaining members explicitly + + Make class 'abstract' 將類別設為 'abstract' @@ -122,6 +277,26 @@ 抑制或設定問題 + + TODO: dispose managed state (managed objects) + TODO: dispose managed state (managed objects) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + + TODO: set large fields to null + TODO: set large fields to 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/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/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 100% rename from src/Features/VisualBasicTest/ImplementAbstractClass/ImplementAbstractClassTests.vb rename to src/Analyzers/VisualBasic/Tests/ImplementAbstractClass/ImplementAbstractClassTests.vb 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 423354c18c0ca..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" 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/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 19f7cbf59e4cb..43f65e0fe045e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -4632,6 +4632,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); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 0478f3c035b08..855c55f91f6c8 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -691,7 +691,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 ? @@ -702,7 +708,7 @@ private BoundCollectionExpression ConvertCollectionExpression( implicitReceiver, diagnostics) : BindCollectionInitializerElementAddMethod( - (ExpressionSyntax)element.Syntax, + element.Syntax, ImmutableArray.Create((BoundExpression)element), hasEnumerableInitializerType: true, collectionInitializerAddMethodBinder, @@ -794,6 +800,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 4c1056aa664e9..d396f67ebdfdf 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -1549,10 +1549,7 @@ 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); - } + ReportFieldContextualKeywordConflictIfAny(node, node.Identifier, diagnostics); if ((object)symbol == null) { @@ -1738,21 +1735,17 @@ void reportPrimaryConstructorParameterShadowing(SimpleNameSyntax node, Symbol sy #nullable enable /// - /// Report a diagnostic for a 'field' or 'value' identifier that the meaning will + /// Report a diagnostic for a 'field' identifier that the meaning will /// change when the identifier is considered a contextual keyword. /// - internal void ReportFieldOrValueContextualKeywordConflictIfAny(SyntaxNode syntax, SyntaxToken identifier, BindingDiagnosticBag diagnostics) + internal void ReportFieldContextualKeywordConflictIfAny(SyntaxNode syntax, SyntaxToken identifier, BindingDiagnosticBag diagnostics) { string name = identifier.Text; - switch (name) + if (name == "field" && + ContainingMember() is MethodSymbol { MethodKind: MethodKind.PropertyGet or MethodKind.PropertySet, AssociatedSymbol: PropertySymbol { IsIndexer: false } }) { - 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; + var requiredVersion = MessageID.IDS_FeatureFieldKeyword.RequiredVersion(); + diagnostics.Add(ErrorCode.INF_IdentifierConflictWithContextualKeyword, syntax, name, requiredVersion.ToDisplayString()); } } #nullable disable @@ -10954,7 +10947,7 @@ static bool isCandidateUnique(ref MethodSymbol? foundMethod, MethodSymbol candid bool satisfiesConstraintChecks(MethodSymbol method) { - if (method.Arity == 0) + if (!ConstraintsHelper.RequiresChecking(method)) { return true; } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 4b429e35c405a..fb5cd361b0184 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -3584,7 +3584,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/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs index 2ab41472ab747..029e78b0bebff 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/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/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs index 0a1d248cbe2cd..160f40f48687e 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) @@ -671,7 +643,7 @@ private Conversion ClassifyStandardImplicitConversion(BoundExpression sourceExpr !conversion.IsInterpolatedStringHandler && !isImplicitCollectionExpressionConversion(conversion)) { - Debug.Assert(IsStandardImplicitConversionFromExpression(conversion.Kind)); + Debug.Assert(isStandardImplicitConversionFromExpression(conversion.Kind)); return conversion; } @@ -691,6 +663,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 11025446502a0..bf36c05d7db92 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs @@ -1822,10 +1822,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. @@ -3231,17 +3236,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, @@ -3520,7 +3514,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 } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index 97441196c52a5..d37137eb5171e 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -661,6 +661,15 @@ + + + + + + - - - - 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/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/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/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/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/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..f73c0fc7d4aca 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 (). @@ -123,10 +119,7 @@ public static class NetFramework /// /// 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; } = [.. Net461.References.All, Net461.ExtraReferences.SystemValueTuple]; /// /// This is a limited set of references on this .NET Framework TFM. This should be avoided in new code @@ -136,18 +129,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 +156,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 +179,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 +238,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 +265,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 +302,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/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/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index fc8157feeaa3f..2e6c6b4a774d1 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) @@ -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/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..bc10843b989ee 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 @@ -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/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/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/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/AttributeTests.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb index b71cb2f002ede..a99bb6fdb3e90 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb @@ -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/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() ~~~~~ ) @@ -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 diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb index 121c12b2f7dd1..d6977b593699d 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb @@ -8126,7 +8126,7 @@ 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) @@ -8210,7 +8210,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 +8328,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 +8436,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 +8568,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 +8701,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) @@ -9072,7 +9072,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)) diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb index d538ab6ee456d..c9f32334c444e 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb @@ -786,7 +786,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) @@ -5382,7 +5382,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) 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/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..0674d5b3c3701 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) 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..8ca31ea3b85b1 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 @@ -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") @@ -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/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/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..af8b346a6f7e3 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() @@ -1188,7 +1188,7 @@ Public Class C End Sub End Class -, {MscorlibRefPortable}) +, {SystemRuntimePP7Ref}) comp.VerifyDiagnostics() 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/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..7b65cbcd40626 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 @@ -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/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/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/WellKnownTypeValidationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb index a5437353524bc..d52c6c203f927 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) @@ -826,6 +826,7 @@ 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 ' Not always available. @@ -1034,6 +1035,7 @@ 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 ' Not always available. 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/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/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/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/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs b/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs index de443b34e138f..e689e61c6dd98 100644 --- a/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs +++ b/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs @@ -9,7 +9,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; using Microsoft.CodeAnalysis.GoToDefinition; @@ -17,7 +16,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.CSharp.InlineRename; @@ -148,7 +146,7 @@ void AddSpanOfInterest(SourceText documentText, TextSpan fallbackSpan, TextSpan? // expand to select the corresponding lines completely. startPosition = documentText.Lines[startLine].Start; endPosition = documentText.Lines[endLine].End; - var length = endPosition - startPosition + 1; + var length = endPosition - startPosition; surroundingSpanOfInterest = new TextSpan(startPosition, length); 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..8ca02f14acabd 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(["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/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 f82c702febe8d..9cea4529f5e2b 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/Rename/CSharpInlineRenameServiceTests.cs b/src/EditorFeatures/CSharpTest/Rename/CSharpInlineRenameServiceTests.cs new file mode 100644 index 0000000000000..91d23795b9359 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/Rename/CSharpInlineRenameServiceTests.cs @@ -0,0 +1,92 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.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 expectedContext = JsonSerializer.Deserialize>>(expectedContextJson); + 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"" : [ ""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/ExtensionKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ExtensionKeywordRecommenderTests.cs index 7ff79a2f29f8d..523a19e6dacc1 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ExtensionKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ExtensionKeywordRecommenderTests.cs @@ -142,9 +142,12 @@ await VerifyKeywordAsync( """); } - [Fact] + [Fact(Skip = "PROTOTYPE")] public async Task TestAfterExtensionDeclaration() { + // PROTOTYPE: errant operator member gets parsed as part of the preceding type + // We need to refine that logic + // See https://github.com/dotnet/roslyn/pull/74495 and IsMemberDeclarationOnlyValidWithinTypeDeclaration await VerifyKeywordAsync( """ implicit extension E { } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs index 89ca1dc86f303..85e256443e1d5 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs @@ -62,8 +62,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) { 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/InlineRename/CommandHandlers/RenameCommandHandler.cs b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs index 57f249768fa80..9283a50c0bf08 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs @@ -94,11 +94,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/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index d3c7a03928798..20f2fe198a151 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -28,7 +28,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 +46,15 @@ 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; 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); @@ -68,25 +67,25 @@ public RenameFlyoutViewModel( 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 +132,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,10 +201,10 @@ public bool IsExpanded } public bool IsRenameOverloadsEditable - => !_session.MustRenameOverloads; + => !Session.MustRenameOverloads; public bool IsRenameOverloadsVisible - => _session.HasRenameOverloads; + => Session.HasRenameOverloads; public TextSpan StartingSelection { get; } @@ -217,14 +216,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 +308,8 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - _session.ReplacementTextChanged -= OnReplacementTextChanged; - _session.ReplacementsComputed -= OnReplacementsComputed; + Session.ReplacementTextChanged -= OnReplacementTextChanged; + Session.ReplacementsComputed -= OnReplacementsComputed; if (SmartRenameViewModel is not null) { diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs index 915123cc5859f..e75ed153380ac 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboardViewModel.cs @@ -16,23 +16,19 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { internal class RenameDashboardViewModel : INotifyPropertyChanged, IDisposable { - private readonly InlineRenameSession _session; - private RenameDashboardSeverity _severity = RenameDashboardSeverity.None; - private string _searchText; private int _resolvableConflictCount; private int _unresolvableConflictCount; - private string _errorText; private bool _isReplacementTextValid; public RenameDashboardViewModel(InlineRenameSession session) { - _session = session; - _searchText = EditorFeaturesResources.Searching; + Session = session; + SearchText = EditorFeaturesResources.Searching; - _session.ReferenceLocationsChanged += OnReferenceLocationsChanged; - _session.ReplacementsComputed += OnReplacementsComputed; - _session.ReplacementTextChanged += OnReplacementTextChanged; + Session.ReferenceLocationsChanged += OnReferenceLocationsChanged; + Session.ReplacementsComputed += OnReplacementsComputed; + Session.ReplacementTextChanged += OnReplacementTextChanged; // Set the flag to true by default if we're showing the option. _isReplacementTextValid = true; @@ -67,7 +63,7 @@ private void OnReplacementsComputed(object sender, IInlineRenameReplacementInfo OnIsReplacementTextValidChanged(result.ReplacementTextValid); if (result.ReplacementTextValid) { - _errorText = null; + ErrorText = null; foreach (var resolution in result.GetAllReplacementKinds()) { switch (resolution) @@ -84,7 +80,7 @@ private void OnReplacementsComputed(object sender, IInlineRenameReplacementInfo } else { - _errorText = string.IsNullOrEmpty(session.ReplacementText) + ErrorText = string.IsNullOrEmpty(session.ReplacementText) ? null : EditorFeaturesResources.The_new_name_is_not_a_valid_identifier; } @@ -113,15 +109,15 @@ private void UpdateSearchText(int referenceCount, int fileCount) { if (referenceCount == 1 && fileCount == 1) { - _searchText = EditorFeaturesResources.Rename_will_update_1_reference_in_1_file; + SearchText = EditorFeaturesResources.Rename_will_update_1_reference_in_1_file; } else if (fileCount == 1) { - _searchText = string.Format(EditorFeaturesResources.Rename_will_update_0_references_in_1_file, referenceCount); + SearchText = string.Format(EditorFeaturesResources.Rename_will_update_0_references_in_1_file, referenceCount); } else { - _searchText = string.Format(EditorFeaturesResources.Rename_will_update_0_references_in_1_files, referenceCount, fileCount); + SearchText = string.Format(EditorFeaturesResources.Rename_will_update_0_references_in_1_files, referenceCount, fileCount); } NotifyPropertyChanged("SearchText"); @@ -129,7 +125,7 @@ private void UpdateSearchText(int referenceCount, int fileCount) private void UpdateSeverity() { - if (_errorText != null || + if (ErrorText != null || _unresolvableConflictCount > 0) { _severity = RenameDashboardSeverity.Error; @@ -144,13 +140,13 @@ private void UpdateSeverity() } } - public InlineRenameSession Session => _session; + public InlineRenameSession Session { get; } public RenameDashboardSeverity Severity => _severity; - public bool AllowFileRename => _session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed && _isReplacementTextValid; - public bool ShowFileRename => _session.FileRenameInfo != InlineRenameFileRenameInfo.NotAllowed; - public string FileRenameString => _session.FileRenameInfo switch + public bool AllowFileRename => Session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed && _isReplacementTextValid; + public bool ShowFileRename => Session.FileRenameInfo != InlineRenameFileRenameInfo.NotAllowed; + public string FileRenameString => Session.FileRenameInfo switch { InlineRenameFileRenameInfo.TypeDoesNotMatchFileName => EditorFeaturesResources.Rename_file_name_doesnt_match, InlineRenameFileRenameInfo.TypeWithMultipleLocations => EditorFeaturesResources.Rename_file_partial_type, @@ -189,7 +185,7 @@ public bool ShouldShowNewName } } - public string SearchText => _searchText; + public string SearchText { get; private set; } public bool HasResolvableConflicts { @@ -222,80 +218,80 @@ public string UnresolvableConflictText } public bool HasError - => _errorText != null; + => ErrorText != null; - public string ErrorText => _errorText; + public string ErrorText { get; private set; } public Visibility RenameOverloadsVisibility - => _session.HasRenameOverloads ? Visibility.Visible : Visibility.Collapsed; + => Session.HasRenameOverloads ? Visibility.Visible : Visibility.Collapsed; public bool IsRenameOverloadsEditable - => !_session.MustRenameOverloads; + => !Session.MustRenameOverloads; public bool DefaultRenameOverloadFlag { - get => _session.Options.RenameOverloads; + get => Session.Options.RenameOverloads; set { if (IsRenameOverloadsEditable) { - _session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameOverloads, value); - _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameOverloads = value }); + Session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameOverloads, value); + Session.RefreshRenameSessionWithOptionsChanged(Session.Options with { RenameOverloads = value }); } } } public bool DefaultRenameInStringsFlag { - get => _session.Options.RenameInStrings; + get => Session.Options.RenameInStrings; set { - _session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInStrings, value); - _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInStrings = value }); + Session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInStrings, value); + Session.RefreshRenameSessionWithOptionsChanged(Session.Options with { RenameInStrings = value }); } } public bool DefaultRenameInCommentsFlag { - get => _session.Options.RenameInComments; + get => Session.Options.RenameInComments; set { - _session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInComments, value); - _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInComments = value }); + Session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInComments, value); + Session.RefreshRenameSessionWithOptionsChanged(Session.Options with { RenameInComments = value }); } } public bool DefaultRenameFileFlag { - get => _session.Options.RenameFile; + get => Session.Options.RenameFile; set { - _session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameFile, value); - _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameFile = value }); + Session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameFile, value); + Session.RefreshRenameSessionWithOptionsChanged(Session.Options with { RenameFile = value }); } } public bool DefaultPreviewChangesFlag { - get => _session.PreviewChanges; + get => Session.PreviewChanges; set { - _session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.PreviewChanges, value); - _session.SetPreviewChanges(value); + Session.RenameService.GlobalOptions.SetGlobalOption(InlineRenameSessionOptionsStorage.PreviewChanges, value); + Session.SetPreviewChanges(value); } } - public string OriginalName => _session.OriginalSymbolName; + public string OriginalName => Session.OriginalSymbolName; public void Dispose() { - _session.ReplacementTextChanged -= OnReplacementTextChanged; - _session.ReferenceLocationsChanged -= OnReferenceLocationsChanged; - _session.ReplacementsComputed -= OnReplacementsComputed; + Session.ReplacementTextChanged -= OnReplacementTextChanged; + Session.ReferenceLocationsChanged -= OnReferenceLocationsChanged; + Session.ReplacementsComputed -= OnReplacementsComputed; } } } diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel.cs index 8b680fae48f6f..46b66cea3c24d 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.EditorFeatures.Lightup; +using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -171,14 +172,21 @@ await Task.Delay(_smartRenameSession.AutomaticFetchDelay, cancellationToken) { var document = this.BaseViewModel.Session.TriggerDocument; var smartRenameContext = ImmutableDictionary.Empty; - var editorRenameService = document.GetRequiredLanguageService(); - var renameLocations = await this.BaseViewModel.Session.AllRenameLocationsTask.JoinAsync(cancellationToken) - .ConfigureAwait(false); - var context = await editorRenameService.GetRenameContextAsync(this.BaseViewModel.Session.RenameInfo, renameLocations, cancellationToken) - .ConfigureAwait(false); - smartRenameContext = ImmutableDictionary.CreateRange( - context - .Select(n => new KeyValuePair(n.Key, n.Value.ToArray()))); + try + { + var editorRenameService = document.GetRequiredLanguageService(); + var renameLocations = await this.BaseViewModel.Session.AllRenameLocationsTask.JoinAsync(cancellationToken) + .ConfigureAwait(false); + var context = await editorRenameService.GetRenameContextAsync(this.BaseViewModel.Session.RenameInfo, renameLocations, cancellationToken) + .ConfigureAwait(false); + smartRenameContext = ImmutableDictionary.CreateRange( + context + .Select(n => new KeyValuePair(n.Key, n.Value.ToArray()))); + } + catch (Exception e) when (FatalError.ReportAndCatch(e, ErrorSeverity.Diagnostic)) + { + // use empty smartRenameContext + } _ = await _smartRenameSession.GetSuggestionsAsync(smartRenameContext, cancellationToken) .ConfigureAwait(false); } diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandHandler.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandHandler.cs index 17fe7a6ca0313..b5a5cd3783323 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandHandler.cs @@ -23,7 +23,6 @@ internal abstract class InteractiveCommandHandler : ICommandHandler, ICommandHandler { - private readonly IContentTypeRegistryService _contentTypeRegistryService; private readonly EditorOptionsService _editorOptionsService; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; @@ -32,12 +31,12 @@ protected InteractiveCommandHandler( EditorOptionsService editorOptionsService, IEditorOperationsFactoryService editorOperationsFactoryService) { - _contentTypeRegistryService = contentTypeRegistryService; + ContentTypeRegistryService = contentTypeRegistryService; _editorOptionsService = editorOptionsService; _editorOperationsFactoryService = editorOperationsFactoryService; } - protected IContentTypeRegistryService ContentTypeRegistryService { get { return _contentTypeRegistryService; } } + protected IContentTypeRegistryService ContentTypeRegistryService { get; } protected abstract IInteractiveWindow OpenInteractiveWindow(bool focus); @@ -62,7 +61,7 @@ bool ICommandHandler.ExecuteCommand(ExecuteInIn var submission = GetSelectedText(args, context.OperationContext.UserCancellationToken); if (!string.IsNullOrWhiteSpace(submission)) { - window.SubmitAsync(new string[] { submission }); + window.SubmitAsync([submission]); } } diff --git a/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs b/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs index 881238c157752..44f9efd6558fd 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs @@ -121,7 +121,7 @@ private async Task ResetInteractiveAsync( if (!string.IsNullOrWhiteSpace(importNamespacesCommand)) { - await interactiveWindow.SubmitAsync(new[] { importNamespacesCommand }).ConfigureAwait(true); + await interactiveWindow.SubmitAsync([importNamespacesCommand]).ConfigureAwait(true); } } diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs index 2b81547c9eac5..6ba12a299a638 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs @@ -101,8 +101,8 @@ private async Task ComputeModelInBackgroundAsync( currentModel.Provider == provider && currentModel.GetCurrentSpanInSubjectBuffer(disconnectedBufferGraph.SubjectBufferSnapshot).Span.Start == items.ApplicableSpan.Start && currentModel.Items.IndexOf(currentModel.SelectedItem) == items.SelectedItemIndex && - currentModel.ArgumentIndex == items.ArgumentIndex && - currentModel.ArgumentCount == items.ArgumentCount && + currentModel.SemanticParameterIndex == items.SemanticParameterIndex && + currentModel.SyntacticArgumentCount == items.SyntacticArgumentCount && currentModel.ArgumentName == items.ArgumentName) { // The new model is the same as the current model. Return the currentModel @@ -112,14 +112,28 @@ private async Task ComputeModelInBackgroundAsync( var selectedItem = GetSelectedItem(currentModel, items, provider, out var userSelected); - var model = new Model(disconnectedBufferGraph, items.ApplicableSpan, provider, - items.Items, selectedItem, items.ArgumentIndex, items.ArgumentCount, items.ArgumentName, - selectedParameter: 0, userSelected); + var model = new Model( + disconnectedBufferGraph, + items.ApplicableSpan, + provider, + items.Items, + selectedItem, + items.SemanticParameterIndex, + items.SyntacticArgumentCount, + items.ArgumentName, + selectedParameter: 0, + userSelected); var syntaxFactsService = document.GetLanguageService(); var isCaseSensitive = syntaxFactsService == null || syntaxFactsService.IsCaseSensitive; - var selection = DefaultSignatureHelpSelector.GetSelection(model.Items, - model.SelectedItem, model.UserSelected, model.ArgumentIndex, model.ArgumentCount, model.ArgumentName, isCaseSensitive); + var selection = DefaultSignatureHelpSelector.GetSelection( + model.Items, + model.SelectedItem, + model.UserSelected, + model.SemanticParameterIndex, + model.SyntacticArgumentCount, + model.ArgumentName, + isCaseSensitive); return model.WithSelectedItem(selection.SelectedItem, selection.UserSelected) .WithSelectedParameter(selection.SelectedParameter); diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_UpdateModel.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_UpdateModel.cs index 6239491682fb3..529bba629961b 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_UpdateModel.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_UpdateModel.cs @@ -20,20 +20,18 @@ internal partial class Session { internal readonly struct SignatureHelpSelection { - private readonly SignatureHelpItem _selectedItem; - private readonly bool _userSelected; private readonly int? _selectedParameter; public SignatureHelpSelection(SignatureHelpItem selectedItem, bool userSelected, int? selectedParameter) : this() { - _selectedItem = selectedItem; - _userSelected = userSelected; + SelectedItem = selectedItem; + UserSelected = userSelected; _selectedParameter = selectedParameter; } public int? SelectedParameter => _selectedParameter; - public SignatureHelpItem SelectedItem => _selectedItem; - public bool UserSelected => _userSelected; + public SignatureHelpItem SelectedItem { get; } + public bool UserSelected { get; } } internal static class DefaultSignatureHelpSelector @@ -42,13 +40,13 @@ public static SignatureHelpSelection GetSelection( IList items, SignatureHelpItem selectedItem, bool userSelected, - int argumentIndex, - int argumentCount, + int semanticParameterIndex, + int syntacticArgumentCount, string argumentName, bool isCaseSensitive) { - SelectBestItem(ref selectedItem, ref userSelected, items, argumentIndex, argumentCount, argumentName, isCaseSensitive); - var selectedParameter = GetSelectedParameter(selectedItem, argumentIndex, argumentName, isCaseSensitive); + SelectBestItem(ref selectedItem, ref userSelected, items, semanticParameterIndex, syntacticArgumentCount, argumentName, isCaseSensitive); + var selectedParameter = GetSelectedParameter(selectedItem, semanticParameterIndex, argumentName, isCaseSensitive); return new SignatureHelpSelection(selectedItem, userSelected, selectedParameter); } @@ -67,12 +65,18 @@ private static int GetSelectedParameter(SignatureHelpItem bestItem, int paramete return parameterIndex; } - private static void SelectBestItem(ref SignatureHelpItem currentItem, ref bool userSelected, - IList filteredItems, int selectedParameter, int argumentCount, string name, bool isCaseSensitive) + private static void SelectBestItem( + ref SignatureHelpItem currentItem, + ref bool userSelected, + IList filteredItems, + int semanticParameterIndex, + int syntacticArgumentCount, + string name, + bool isCaseSensitive) { // If the current item is still applicable, then just keep it. if (filteredItems.Contains(currentItem) && - IsApplicable(currentItem, argumentCount, name, isCaseSensitive)) + IsApplicable(currentItem, syntacticArgumentCount, name, isCaseSensitive)) { // If the current item was user-selected, we keep it as such. return; @@ -86,7 +90,7 @@ private static void SelectBestItem(ref SignatureHelpItem currentItem, ref bool u // selected parameter was outside the bounds of all methods. i.e. all methods only // went up to 3 parameters, and selected parameter is 3 or higher. In that case, // just pick the very last item as it is closest in parameter count. - var result = filteredItems.FirstOrDefault(i => IsApplicable(i, argumentCount, name, isCaseSensitive)); + var result = filteredItems.FirstOrDefault(i => IsApplicable(i, syntacticArgumentCount, name, isCaseSensitive)); if (result != null) { currentItem = result; @@ -97,7 +101,7 @@ private static void SelectBestItem(ref SignatureHelpItem currentItem, ref bool u // a name. if (name != null) { - SelectBestItem(ref currentItem, ref userSelected, filteredItems, selectedParameter, argumentCount, null, isCaseSensitive); + SelectBestItem(ref currentItem, ref userSelected, filteredItems, semanticParameterIndex, syntacticArgumentCount, null, isCaseSensitive); return; } @@ -112,7 +116,7 @@ private static void SelectBestItem(ref SignatureHelpItem currentItem, ref bool u currentItem = lastItem; } - private static bool IsApplicable(SignatureHelpItem item, int argumentCount, string name, bool isCaseSensitive) + private static bool IsApplicable(SignatureHelpItem item, int syntacticArgumentCount, string name, bool isCaseSensitive) { // If they provided a name, then the item is only valid if it has a parameter that // matches that name. @@ -126,7 +130,7 @@ private static bool IsApplicable(SignatureHelpItem item, int argumentCount, stri // parameter index. i.e. if it has 2 parameters and we're at index 0 or 1 then it's // applicable. However, if it has 2 parameters and we're at index 2, then it's not // applicable. - if (item.Parameters.Length >= argumentCount) + if (item.Parameters.Length >= syntacticArgumentCount) { return true; } @@ -141,7 +145,7 @@ private static bool IsApplicable(SignatureHelpItem item, int argumentCount, stri // Also, we special case 0. that's because if the user has "Goo(" and goo takes no // arguments, then we'll see that it's arg count is 0. We still want to consider // any item applicable here though. - return argumentCount == 0; + return syntacticArgumentCount == 0; } } } diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Model.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Model.cs index a128a4c7f8002..00d210ad0890c 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Model.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Model.cs @@ -23,8 +23,12 @@ internal class Model /// UserSelected is true if the SelectedItem is the result of a user selection (up/down arrows). public bool UserSelected { get; } - public int ArgumentIndex { get; } - public int ArgumentCount { get; } + + /// + public int SemanticParameterIndex { get; } + + /// + public int SyntacticArgumentCount { get; } public string ArgumentName { get; } public int? SelectedParameter { get; } public ISignatureHelpProvider Provider { get; } @@ -35,8 +39,8 @@ public Model( ISignatureHelpProvider provider, IList items, SignatureHelpItem selectedItem, - int argumentIndex, - int argumentCount, + int semanticParameterIndex, + int syntacticArgumentCount, string argumentName, int? selectedParameter, bool userSelected) @@ -51,8 +55,8 @@ public Model( this.Provider = provider; this.SelectedItem = selectedItem; this.UserSelected = userSelected; - this.ArgumentIndex = argumentIndex; - this.ArgumentCount = argumentCount; + this.SemanticParameterIndex = semanticParameterIndex; + this.SyntacticArgumentCount = syntacticArgumentCount; this.ArgumentName = argumentName; this.SelectedParameter = selectedParameter; } @@ -61,14 +65,14 @@ public Model WithSelectedItem(SignatureHelpItem selectedItem, bool userSelected) { return selectedItem == this.SelectedItem && userSelected == this.UserSelected ? this - : new Model(_disconnectedBufferGraph, TextSpan, Provider, Items, selectedItem, ArgumentIndex, ArgumentCount, ArgumentName, SelectedParameter, userSelected); + : new Model(_disconnectedBufferGraph, TextSpan, Provider, Items, selectedItem, SemanticParameterIndex, SyntacticArgumentCount, ArgumentName, SelectedParameter, userSelected); } public Model WithSelectedParameter(int? selectedParameter) { return selectedParameter == this.SelectedParameter ? this - : new Model(_disconnectedBufferGraph, TextSpan, Provider, Items, SelectedItem, ArgumentIndex, ArgumentCount, ArgumentName, selectedParameter, UserSelected); + : new Model(_disconnectedBufferGraph, TextSpan, Provider, Items, SelectedItem, SemanticParameterIndex, SyntacticArgumentCount, ArgumentName, selectedParameter, UserSelected); } public SnapshotSpan GetCurrentSpanInSubjectBuffer(ITextSnapshot bufferSnapshot) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixMultipleOccurrencesService.cs b/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixMultipleOccurrencesService.cs index a95dba33462e5..5268050b4926c 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixMultipleOccurrencesService.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixMultipleOccurrencesService.cs @@ -35,7 +35,6 @@ public Solution GetFix( Workspace workspace, CodeFixProvider fixProvider, FixAllProvider fixAllProvider, - CodeActionOptionsProvider optionsProvider, string equivalenceKey, string waitDialogTitle, string waitDialogMessage, @@ -43,7 +42,7 @@ public Solution GetFix( CancellationToken cancellationToken) { var fixMultipleState = FixAllState.Create( - fixAllProvider, diagnosticsToFix, fixProvider, equivalenceKey, optionsProvider); + fixAllProvider, diagnosticsToFix, fixProvider, equivalenceKey); return GetFixedSolution( fixMultipleState, workspace, waitDialogTitle, waitDialogMessage, progress, cancellationToken); @@ -54,7 +53,6 @@ public Solution GetFix( Workspace workspace, CodeFixProvider fixProvider, FixAllProvider fixAllProvider, - CodeActionOptionsProvider optionsProvider, string equivalenceKey, string waitDialogTitle, string waitDialogMessage, @@ -62,7 +60,7 @@ public Solution GetFix( CancellationToken cancellationToken) { var fixMultipleState = FixAllState.Create( - fixAllProvider, diagnosticsToFix, fixProvider, equivalenceKey, optionsProvider); + fixAllProvider, diagnosticsToFix, fixProvider, equivalenceKey); return GetFixedSolution( fixMultipleState, workspace, waitDialogTitle, waitDialogMessage, progress, cancellationToken); diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 7a6a29d9512d8..91222cfcb6840 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -188,14 +188,12 @@ private void OnTextViewClosed(object sender, EventArgs e) if (document == null) return null; - var fallbackOptions = GlobalOptions.GetCodeActionOptionsProvider(); - using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); // Assign over cancellation token so no one accidentally uses the wrong token. cancellationToken = linkedTokenSource.Token; // Kick off the work to get errors. - var errorTask = GetFixLevelAsync(document, range, fallbackOptions, cancellationToken); + var errorTask = GetFixLevelAsync(document, range, cancellationToken); // Make a quick jump back to the UI thread to get the user's selection, then go back to the thread pool.. await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); @@ -205,7 +203,7 @@ private void OnTextViewClosed(object sender, EventArgs e) // If we have a selection, kick off the work to get refactorings concurrently with the above work to get errors. var refactoringTask = selection != null - ? TryGetRefactoringSuggestedActionCategoryAsync(document, selection, fallbackOptions, cancellationToken) + ? TryGetRefactoringSuggestedActionCategoryAsync(document, selection, cancellationToken) : SpecializedTasks.Null(); // If we happen to get the result of the error task before the refactoring task, @@ -221,7 +219,6 @@ private void OnTextViewClosed(object sender, EventArgs e) private async Task GetFixLevelAsync( TextDocument document, SnapshotSpan range, - CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { // Ensure we yield the thread that called into us, allowing it to continue onwards. @@ -254,7 +251,7 @@ private void OnTextViewClosed(object sender, EventArgs e) state.Target.SubjectBuffer.SupportsCodeFixes()) { var result = await state.Target.Owner._codeFixService.GetMostSevereFixAsync( - document, range.Span.ToTextSpan(), priorityProvider, fallbackOptions, cancellationToken).ConfigureAwait(false); + document, range.Span.ToTextSpan(), priorityProvider, cancellationToken).ConfigureAwait(false); if (result != null) { @@ -276,7 +273,6 @@ private void OnTextViewClosed(object sender, EventArgs e) private async Task TryGetRefactoringSuggestedActionCategoryAsync( TextDocument document, TextSpan? selection, - CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { // Ensure we yield the thread that called into us, allowing it to continue onwards. @@ -300,7 +296,7 @@ private void OnTextViewClosed(object sender, EventArgs e) state.Target.SubjectBuffer.SupportsRefactorings()) { if (await state.Target.Owner._codeRefactoringService.HasRefactoringsAsync( - document, selection.Value, fallbackOptions, cancellationToken).ConfigureAwait(false)) + document, selection.Value, cancellationToken).ConfigureAwait(false)) { return PredefinedSuggestedActionCategoryNames.Refactoring; } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs index e677293685c06..7f4c8382432b9 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs @@ -211,8 +211,6 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs var workspace = document.Project.Solution.Workspace; var supportsFeatureService = workspace.Services.GetRequiredService(); - var options = GlobalOptions.GetCodeActionOptionsProvider(); - var fixesTask = GetCodeFixesAsync(); var refactoringsTask = GetRefactoringsAsync(); @@ -242,7 +240,7 @@ async Task> GetCodeFixesAsync() return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( workspace, owner._codeFixService, document, range.Span.ToTextSpan(), - priorityProvider, options, cancellationToken).ConfigureAwait(false); + priorityProvider, cancellationToken).ConfigureAwait(false); } async Task> GetRefactoringsAsync() @@ -273,7 +271,7 @@ async Task> GetRefactoringsAsync() var filterOutsideSelection = !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.Refactoring); return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - workspace, owner._codeRefactoringService, document, selection.Value, priorityProvider.Priority, options, + workspace, owner._codeRefactoringService, document, selection.Value, priorityProvider.Priority, filterOutsideSelection, cancellationToken).ConfigureAwait(false); } diff --git a/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs b/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs index d6b7430e5049e..fd323fe673b2d 100644 --- a/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs +++ b/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs @@ -36,9 +36,8 @@ internal class CodeActionEditHandlerService( private readonly IThreadingContext _threadingContext = threadingContext; private readonly IPreviewFactoryService _previewService = previewService; private readonly IInlineRenameService _renameService = renameService; - private readonly ITextBufferAssociatedViewService _associatedViewService = associatedViewService; - public ITextBufferAssociatedViewService AssociatedViewService => _associatedViewService; + public ITextBufferAssociatedViewService AssociatedViewService { get; } = associatedViewService; public async Task GetPreviewsAsync( Workspace workspace, ImmutableArray operations, CancellationToken cancellationToken) diff --git a/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs b/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs index 15642db98bd89..93a157f97d471 100644 --- a/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs +++ b/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs @@ -319,17 +319,16 @@ public async ValueTask GetUpdatesAsync(CancellationToke var designTimeSolution = GetCurrentDesignTimeSolution(); var solution = GetCurrentCompileTimeSolution(designTimeSolution); var activeStatementSpanProvider = GetActiveStatementSpanProvider(solution); - var (moduleUpdates, diagnosticData, rudeEdits, syntaxError) = await GetDebuggingSession().EmitSolutionUpdateAsync(solution, activeStatementSpanProvider, cancellationToken).ConfigureAwait(false); + var result = await GetDebuggingSession().EmitSolutionUpdateAsync(solution, activeStatementSpanProvider, cancellationToken).ConfigureAwait(false); // Only store the solution if we have any changes to apply, otherwise CommitUpdatesAsync/DiscardUpdatesAsync won't be called. - if (moduleUpdates.Status == ModuleUpdateStatus.Ready) + if (result.ModuleUpdates.Status == ModuleUpdateStatus.Ready) { _pendingUpdatedDesignTimeSolution = designTimeSolution; } - UpdateApplyChangesDiagnostics(diagnosticData); + UpdateApplyChangesDiagnostics(result.Diagnostics); - var diagnostics = await EmitSolutionUpdateResults.GetAllDiagnosticsAsync(solution, diagnosticData, rudeEdits, syntaxError, moduleUpdates.Status, cancellationToken).ConfigureAwait(false); - return new ManagedHotReloadUpdates(moduleUpdates.Updates.FromContract(), diagnostics.FromContract()); + return new ManagedHotReloadUpdates(result.ModuleUpdates.Updates.FromContract(), result.GetAllDiagnostics().FromContract()); } } diff --git a/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs b/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs index dfb8771affe5f..923049a4c1d8b 100644 --- a/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs +++ b/src/EditorFeatures/Core/Editor/GoToAdjacentMemberCommandHandler.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using System.Collections.Generic; using System.ComponentModel.Composition; using System.Linq; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -17,7 +18,9 @@ using Microsoft.VisualStudio.Text.Editor.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Text.Outlining; -using Microsoft.VisualStudio.Utilities; + +using ContentTypeAttribute = Microsoft.VisualStudio.Utilities.ContentTypeAttribute; +using NameAttribute = Microsoft.VisualStudio.Utilities.NameAttribute; namespace Microsoft.CodeAnalysis.Editor; @@ -100,7 +103,8 @@ private bool ExecuteCommandImpl(EditorCommandArgs args, bool gotoNextMember, Com /// internal static int? GetTargetPosition(ISyntaxFactsService service, SyntaxNode root, int caretPosition, bool next) { - var members = service.GetMethodLevelMembers(root); + using var pooledMembers = service.GetMethodLevelMembers(root); + var members = pooledMembers.Object; if (members.Count == 0) { return null; diff --git a/src/EditorFeatures/Core/Extensibility/Commands/PredefinedCommandHandlerNames.cs b/src/EditorFeatures/Core/Extensibility/Commands/PredefinedCommandHandlerNames.cs index c6e58829f10e1..43a3d4f969a00 100644 --- a/src/EditorFeatures/Core/Extensibility/Commands/PredefinedCommandHandlerNames.cs +++ b/src/EditorFeatures/Core/Extensibility/Commands/PredefinedCommandHandlerNames.cs @@ -133,12 +133,6 @@ internal static class PredefinedCommandHandlerNames ///
public const string Rename = "Rename Command Handler"; - /// - /// Command handler for detecting user save commands, and using that to issue a request to run source generators - /// (when in mode). - /// - public const string SourceGeneratorSave = "Source Generator Save Command Handler"; - /// /// Command handler name for Rename Tracking cancellation. /// diff --git a/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarSelectedItems.cs b/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarSelectedItems.cs index 0146b46a71dc0..ea1cd0bc16d0a 100644 --- a/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarSelectedItems.cs +++ b/src/EditorFeatures/Core/Extensibility/NavigationBar/NavigationBarSelectedItems.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Editor; -internal class NavigationBarSelectedTypeAndMember( +internal sealed class NavigationBarSelectedTypeAndMember( NavigationBarItem? typeItem, bool showTypeItemGrayed, NavigationBarItem? memberItem, diff --git a/src/EditorFeatures/Core/Extensibility/NavigationBar/WrappedNavigationBarItem.cs b/src/EditorFeatures/Core/Extensibility/NavigationBar/WrappedNavigationBarItem.cs index d123648303e91..47f2e62ebe42e 100644 --- a/src/EditorFeatures/Core/Extensibility/NavigationBar/WrappedNavigationBarItem.cs +++ b/src/EditorFeatures/Core/Extensibility/NavigationBar/WrappedNavigationBarItem.cs @@ -26,7 +26,7 @@ internal WrappedNavigationBarItem(ITextVersion textVersion, RoslynNavigationBarI underlyingItem.Text, underlyingItem.Glyph, GetSpans(underlyingItem), - underlyingItem.ChildItems.SelectAsArray(v => (NavigationBarItem)new WrappedNavigationBarItem(textVersion, v)), + underlyingItem.ChildItems.SelectAsArray(static (v, textVersion) => (NavigationBarItem)new WrappedNavigationBarItem(textVersion, v), textVersion), underlyingItem.Indent, underlyingItem.Bolded, underlyingItem.Grayed) diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.cs index cf44afca54f38..4d5c099549a6f 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptEditorInlineRenameService.cs @@ -14,5 +14,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; ///
internal abstract class VSTypeScriptEditorInlineRenameServiceImplementation { + public virtual bool IsEnabled() => true; + public abstract Task GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken); } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptGlobalOptions.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptGlobalOptions.cs index fe33d18f6e4f4..8ea4db54ca5ea 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptGlobalOptions.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptGlobalOptions.cs @@ -16,22 +16,20 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api; [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] internal sealed class VSTypeScriptGlobalOptions(IGlobalOptionService globalOptions) { - private readonly IGlobalOptionService _globalOptions = globalOptions; - public bool BlockForCompletionItems { - get => _globalOptions.GetOption(CompletionViewOptionsStorage.BlockForCompletionItems, InternalLanguageNames.TypeScript); - set => _globalOptions.SetGlobalOption(CompletionViewOptionsStorage.BlockForCompletionItems, InternalLanguageNames.TypeScript, value); + get => Service.GetOption(CompletionViewOptionsStorage.BlockForCompletionItems, InternalLanguageNames.TypeScript); + set => Service.SetGlobalOption(CompletionViewOptionsStorage.BlockForCompletionItems, InternalLanguageNames.TypeScript, value); } public void SetBackgroundAnalysisScope(bool openFilesOnly) { - _globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, InternalLanguageNames.TypeScript, + Service.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, InternalLanguageNames.TypeScript, openFilesOnly ? BackgroundAnalysisScope.OpenFiles : BackgroundAnalysisScope.FullSolution); - _globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, InternalLanguageNames.TypeScript, + Service.SetGlobalOption(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, InternalLanguageNames.TypeScript, openFilesOnly ? CompilerDiagnosticsScope.OpenFiles : CompilerDiagnosticsScope.FullSolution); - _globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.RemoveDocumentDiagnosticsOnDocumentClose, InternalLanguageNames.TypeScript, + Service.SetGlobalOption(SolutionCrawlerOptionsStorage.RemoveDocumentDiagnosticsOnDocumentClose, InternalLanguageNames.TypeScript, openFilesOnly); } @@ -41,5 +39,5 @@ public void SetBackgroundAnalysisScope(Workspace workspace, bool openFilesOnly) => SetBackgroundAnalysisScope(openFilesOnly); #pragma warning restore - internal IGlobalOptionService Service => _globalOptions; + internal IGlobalOptionService Service { get; } = globalOptions; } diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs index 4f88d81441d64..6eedff8207eaa 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptEditorInlineRenameService.cs @@ -24,6 +24,19 @@ internal sealed class VSTypeScriptEditorInlineRenameService( { private readonly Lazy? _service = service; + public bool IsEnabled + { + get + { + if (_service != null) + { + return _service.Value.IsEnabled(); + } + + return false; + } + } + public Task>> GetRenameContextAsync(IInlineRenameInfo inlineRenameInfo, IInlineRenameLocationSet inlineRenameLocationSet, CancellationToken cancellationToken) { return Task.FromResult(ImmutableDictionary>.Empty); diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptRequestExecutionQueueProvider.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptRequestExecutionQueueProvider.cs index 121d529769011..e2097d53c6631 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptRequestExecutionQueueProvider.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptRequestExecutionQueueProvider.cs @@ -7,22 +7,19 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CommonLanguageServerProtocol.Framework; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript; [ExportStatelessLspService(typeof(IRequestExecutionQueueProvider), ProtocolConstants.TypeScriptLanguageContract), Shared] -internal sealed class VSTypeScriptRequestExecutionQueueProvider : IRequestExecutionQueueProvider +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, true)] +internal sealed class VSTypeScriptRequestExecutionQueueProvider(IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider) : IRequestExecutionQueueProvider { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, true)] - public VSTypeScriptRequestExecutionQueueProvider() - { - } - 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/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs index 6d08010693760..4c5351e60b5c7 100644 --- a/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs +++ b/src/EditorFeatures/Core/ExtractMethod/ExtractMethodCommandHandler.cs @@ -88,7 +88,7 @@ public bool ExecuteCommand(ExtractMethodCommandArgs args, CommandExecutionContex // wait indicator for Extract Method if (_renameService.ActiveSession != null) { - _threadingContext.JoinableTaskFactory.Run(() => _renameService.ActiveSession.CommitAsync(previewChanges: false, CancellationToken.None)); + _threadingContext.JoinableTaskFactory.Run(() => _renameService.ActiveSession.CommitAsync(previewChanges: false, context.OperationContext)); } if (!args.SubjectBuffer.SupportsRefactorings()) diff --git a/src/EditorFeatures/Core/IInlineRenameSession.cs b/src/EditorFeatures/Core/IInlineRenameSession.cs index 3ae70a4d091a2..f644a16a423b5 100644 --- a/src/EditorFeatures/Core/IInlineRenameSession.cs +++ b/src/EditorFeatures/Core/IInlineRenameSession.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.VisualStudio.Utilities; namespace Microsoft.CodeAnalysis.Editor; @@ -43,12 +44,13 @@ internal InlineRenameSessionInfo(IInlineRenameSession session) internal interface IInlineRenameSession { /// - /// Cancels the rename session, and undoes any edits that had been performed by the session. + /// Cancels the rename session, and undoes any edits that had been performed by the session. Must be called on the + /// UI thread. /// void Cancel(); /// /// Dismisses the rename session, completing the rename operation across all files. /// - Task CommitAsync(bool previewChanges, CancellationToken cancellationToken); + Task CommitAsync(bool previewChanges, IUIThreadOperationContext editorOperationContext = null); } diff --git a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs index 953187dae7267..621b10356c3b0 100644 --- a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs @@ -20,6 +20,8 @@ protected AbstractEditorInlineRenameService(IEnumerable _refactorNotifyServices = refactorNotifyServices; } + public bool IsEnabled => true; + public async Task GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken) { var symbolicInfo = await SymbolicRenameInfo.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs index 3a54313a64f99..327254149e670 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler.cs @@ -11,6 +11,8 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding; +using Microsoft.VisualStudio.Utilities; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; @@ -55,7 +57,7 @@ private CommandState GetCommandState(Func nextHandler) private CommandState GetCommandState() => _renameService.ActiveSession != null ? CommandState.Available : CommandState.Unspecified; - private void HandlePossibleTypingCommand(TArgs args, Action nextHandler, Action actionIfInsideActiveSpan) + private void HandlePossibleTypingCommand(TArgs args, Action nextHandler, IUIThreadOperationContext operationContext, Action actionIfInsideActiveSpan) where TArgs : EditorCommandArgs { if (_renameService.ActiveSession == null) @@ -78,14 +80,14 @@ private void HandlePossibleTypingCommand(TArgs args, Action nextHandler, if (_renameService.ActiveSession.TryGetContainingEditableSpan(singleSpan.Start, out var containingSpan) && containingSpan.Contains(singleSpan)) { - actionIfInsideActiveSpan(_renameService.ActiveSession, containingSpan); + actionIfInsideActiveSpan(_renameService.ActiveSession, operationContext, containingSpan); } else if (_renameService.ActiveSession.IsInOpenTextBuffer(singleSpan.Start)) { // It's in a read-only area that is open, so let's commit the rename // and then let the character go through - CommitIfActiveAndCallNextHandler(args, nextHandler); + CommitIfActiveAndCallNextHandler(args, nextHandler, operationContext); } else { @@ -94,13 +96,13 @@ private void HandlePossibleTypingCommand(TArgs args, Action nextHandler, } } - private void CommitIfActive(EditorCommandArgs args) + private void CommitIfActive(EditorCommandArgs args, IUIThreadOperationContext operationContext) { if (_renameService.ActiveSession != null) { var selection = args.TextView.Selection.VirtualSelectedSpans.First(); - _renameService.ActiveSession.Commit(); + Commit(operationContext); var translatedSelection = selection.TranslateTo(args.TextView.TextBuffer.CurrentSnapshot); args.TextView.Selection.Select(translatedSelection.Start, translatedSelection.End); @@ -108,9 +110,15 @@ private void CommitIfActive(EditorCommandArgs args) } } - private void CommitIfActiveAndCallNextHandler(EditorCommandArgs args, Action nextHandler) + private void CommitIfActiveAndCallNextHandler(EditorCommandArgs args, Action nextHandler, IUIThreadOperationContext operationContext) { - CommitIfActive(args); + CommitIfActive(args, operationContext); nextHandler(); } + + private void Commit(IUIThreadOperationContext operationContext) + { + RoslynDebug.AssertNotNull(_renameService.ActiveSession); + _renameService.ActiveSession.Commit(previewChanges: false, operationContext); + } } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_BackspaceDeleteHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_BackspaceDeleteHandler.cs index 21c6c04c1dea9..d068c352e5600 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_BackspaceDeleteHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_BackspaceDeleteHandler.cs @@ -21,7 +21,7 @@ public CommandState GetCommandState(DeleteKeyCommandArgs args, Func + HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, _, span) => { var caretPoint = args.TextView.GetCaretPoint(args.SubjectBuffer); if (!args.TextView.Selection.IsEmpty || caretPoint.Value != span.Start) @@ -33,7 +33,7 @@ public void ExecuteCommand(BackspaceKeyCommandArgs args, Action nextHandler, Com public void ExecuteCommand(DeleteKeyCommandArgs args, Action nextHandler, CommandExecutionContext context) { - HandlePossibleTypingCommand(args, nextHandler, (activeSession, span) => + HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, _, span) => { var caretPoint = args.TextView.GetCaretPoint(args.SubjectBuffer); if (!args.TextView.Selection.IsEmpty || caretPoint.Value != span.End) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_CutPasteHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_CutPasteHandler.cs index 3448d2eda764c..89affbfabdeb9 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_CutPasteHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_CutPasteHandler.cs @@ -16,7 +16,7 @@ public CommandState GetCommandState(CutCommandArgs args, Func next public void ExecuteCommand(CutCommandArgs args, Action nextHandler, CommandExecutionContext context) { - HandlePossibleTypingCommand(args, nextHandler, (activeSession, span) => + HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, _, span) => { nextHandler(); }); @@ -27,7 +27,7 @@ public CommandState GetCommandState(PasteCommandArgs args, Func ne public void ExecuteCommand(PasteCommandArgs args, Action nextHandler, CommandExecutionContext context) { - HandlePossibleTypingCommand(args, nextHandler, (activeSession, span) => + HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, _, span) => { nextHandler(); }); diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_MoveSelectedLinesHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_MoveSelectedLinesHandler.cs index ffee45ee36f18..e9a140815a143 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_MoveSelectedLinesHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_MoveSelectedLinesHandler.cs @@ -15,7 +15,7 @@ public CommandState GetCommandState(MoveSelectedLinesUpCommandArgs args) public bool ExecuteCommand(MoveSelectedLinesUpCommandArgs args, CommandExecutionContext context) { - CommitIfActive(args); + CommitIfActive(args, context.OperationContext); return false; } @@ -24,7 +24,7 @@ public CommandState GetCommandState(MoveSelectedLinesDownCommandArgs args) public bool ExecuteCommand(MoveSelectedLinesDownCommandArgs args, CommandExecutionContext context) { - CommitIfActive(args); + CommitIfActive(args, context.OperationContext); return false; } } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs index 6670627524316..830552a35e14c 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineAboveHandler.cs @@ -15,9 +15,9 @@ public CommandState GetCommandState(OpenLineAboveCommandArgs args, Func + HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, operationContext, span) => { - activeSession.Commit(); + Commit(operationContext); nextHandler(); }); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs index e8649fbf5577c..5bb99425cdae2 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_OpenLineBelowHandler.cs @@ -15,9 +15,9 @@ public CommandState GetCommandState(OpenLineBelowCommandArgs args, Func + HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, operationContext, span) => { - activeSession.Commit(); + Commit(operationContext); nextHandler(); }); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RefactoringWithCommandHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RefactoringWithCommandHandler.cs index 8c403e0d14712..a3413138c2e74 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RefactoringWithCommandHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RefactoringWithCommandHandler.cs @@ -18,7 +18,7 @@ public CommandState GetCommandState(ReorderParametersCommandArgs args) public bool ExecuteCommand(ReorderParametersCommandArgs args, CommandExecutionContext context) { - CommitIfActive(args); + CommitIfActive(args, context.OperationContext); return false; } @@ -27,7 +27,7 @@ public CommandState GetCommandState(RemoveParametersCommandArgs args) public bool ExecuteCommand(RemoveParametersCommandArgs args, CommandExecutionContext context) { - CommitIfActive(args); + CommitIfActive(args, context.OperationContext); return false; } @@ -36,7 +36,7 @@ public CommandState GetCommandState(ExtractInterfaceCommandArgs args) public bool ExecuteCommand(ExtractInterfaceCommandArgs args, CommandExecutionContext context) { - CommitIfActive(args); + CommitIfActive(args, context.OperationContext); return false; } @@ -45,7 +45,7 @@ public CommandState GetCommandState(EncapsulateFieldCommandArgs args) public bool ExecuteCommand(EncapsulateFieldCommandArgs args, CommandExecutionContext context) { - CommitIfActive(args); + CommitIfActive(args, context.OperationContext); return false; } } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs index 3824c17c70742..8fce77aa75c2b 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_RenameHandler.cs @@ -9,9 +9,12 @@ using Microsoft.CodeAnalysis.Editor.BackgroundWorkIndicator; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Notification; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Microsoft.VisualStudio.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; @@ -41,11 +44,11 @@ public bool ExecuteCommand(RenameCommandArgs args, CommandExecutionContext conte } var token = _listener.BeginAsyncOperation(nameof(ExecuteCommand)); - _ = ExecuteCommandAsync(args).CompletesAsyncOperation(token); + _ = ExecuteCommandAsync(args, context.OperationContext).CompletesAsyncOperation(token); return true; } - private async Task ExecuteCommandAsync(RenameCommandArgs args) + private async Task ExecuteCommandAsync(RenameCommandArgs args, IUIThreadOperationContext editorOperationContext) { _threadingContext.ThrowIfNotOnUIThread(); @@ -61,12 +64,6 @@ private async Task ExecuteCommandAsync(RenameCommandArgs args) return; } - var backgroundWorkIndicatorFactory = workspace.Services.GetRequiredService(); - using var context = backgroundWorkIndicatorFactory.Create( - args.TextView, - args.TextView.GetTextElementSpan(caretPoint.Value), - EditorFeaturesResources.Finding_token_to_rename); - // If there is already an active session, commit it first if (_renameService.ActiveSession != null) { @@ -80,10 +77,16 @@ private async Task ExecuteCommandAsync(RenameCommandArgs args) else { // Otherwise, commit the existing session and start a new one. - _renameService.ActiveSession.Commit(); + Commit(editorOperationContext); } } + var backgroundWorkIndicatorFactory = workspace.Services.GetRequiredService(); + using var context = backgroundWorkIndicatorFactory.Create( + args.TextView, + args.TextView.GetTextElementSpan(caretPoint.Value), + EditorFeaturesResources.Finding_token_to_rename); + var cancellationToken = context.UserCancellationToken; var document = await args @@ -120,6 +123,9 @@ private static bool CanRename(RenameCommandArgs args) { return args.SubjectBuffer.TryGetWorkspace(out var workspace) && workspace.CanApplyChange(ApplyChangesKind.ChangeDocument) && + args.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges() is Document document && + document.GetLanguageService() is IEditorInlineRenameService inlineRenameService && + inlineRenameService.IsEnabled && args.SubjectBuffer.SupportsRename() && !args.SubjectBuffer.IsInLspEditorContext(); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs index 5cb04c3f18579..db18065f46759 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_ReturnHandler.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Microsoft.VisualStudio.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; @@ -17,20 +18,16 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co { if (_renameService.ActiveSession != null) { - // Prevent Editor's typing responsiveness auto canceling the rename operation. - // InlineRenameSession will call IUIThreadOperationExecutor to sets up our own IUIThreadOperationContext - context.OperationContext.TakeOwnership(); - - Commit(_renameService.ActiveSession, args.TextView); + CommitAndSetFocus(_renameService.ActiveSession, args.TextView, context.OperationContext); return true; } return false; } - protected virtual void Commit(InlineRenameSession activeSession, ITextView textView) + protected virtual void CommitAndSetFocus(InlineRenameSession activeSession, ITextView textView, IUIThreadOperationContext operationContext) { - activeSession.Commit(); + Commit(operationContext); SetFocusToTextView(textView); } } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs index 4a9bb0c50b1e1..132c8d0f42a5d 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_SaveHandler.cs @@ -16,7 +16,7 @@ public bool ExecuteCommand(SaveCommandArgs args, CommandExecutionContext context { if (_renameService.ActiveSession != null) { - _renameService.ActiveSession.Commit(); + Commit(context.OperationContext); SetFocusToTextView(args.TextView); } diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TabHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TabHandler.cs index b7cff5b4ed1c7..9846afad5f315 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TabHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TabHandler.cs @@ -26,7 +26,7 @@ public void ExecuteCommand(TabKeyCommandArgs args, Action nextHandler, CommandEx return; } - HandlePossibleTypingCommand(args, nextHandler, (activeSession, span) => + HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, _, span) => { var spans = new NormalizedSnapshotSpanCollection( activeSession.GetBufferManager(args.SubjectBuffer) diff --git a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TypeCharHandler.cs b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TypeCharHandler.cs index 6b1da07bed52b..d154e4f9fc438 100644 --- a/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TypeCharHandler.cs +++ b/src/EditorFeatures/Core/InlineRename/CommandHandlers/AbstractRenameCommandHandler_TypeCharHandler.cs @@ -19,7 +19,7 @@ public CommandState GetCommandState(TypeCharCommandArgs args, Func public void ExecuteCommand(TypeCharCommandArgs args, Action nextHandler, CommandExecutionContext context) { - HandlePossibleTypingCommand(args, nextHandler, (activeSession, span) => + HandlePossibleTypingCommand(args, nextHandler, context.OperationContext, (activeSession, _, span) => { var document = args.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) diff --git a/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs b/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs index ad4d3583fafd5..34d27e4fb43e0 100644 --- a/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/InlineRename/IEditorInlineRenameService.cs @@ -254,6 +254,12 @@ internal interface IInlineRenameInfo ///
internal interface IEditorInlineRenameService : ILanguageService { + /// + /// Returns true if the service is currently enabled for the language (e.g. the value + /// might depend on a feature flag.) + /// + bool IsEnabled { get; } + /// /// Returns necessary to establish the inline rename session. /// diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs index c57dddfb0a9d0..01c02a309551b 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs @@ -185,7 +185,7 @@ internal void SetReferenceSpans(IEnumerable spans) foreach (var span in spans) { var document = _baseDocuments.First(); - var renameableSpan = _session._renameInfo.GetReferenceEditSpan( + var renameableSpan = _session.RenameInfo.GetReferenceEditSpan( new InlineRenameLocation(document, span), GetTriggerText(document, span), CancellationToken.None); var trackingSpan = new RenameTrackingSpan( _subjectBuffer.CurrentSnapshot.CreateTrackingSpan(renameableSpan.ToSpan(), SpanTrackingMode.EdgeInclusive, TrackingFidelityMode.Forward), @@ -470,7 +470,7 @@ internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflict if (_referenceSpanToLinkedRenameSpanMap.ContainsKey(replacement.OriginalSpan) && kind != RenameSpanKind.Complexified) { - var linkedRenameSpan = _session._renameInfo.GetConflictEditSpan( + var linkedRenameSpan = _session.RenameInfo.GetConflictEditSpan( new InlineRenameLocation(newDocument, replacement.NewSpan), GetTriggerText(newDocument, replacement.NewSpan), GetWithoutAttributeSuffix(_session.ReplacementText, document.GetLanguageService().IsCaseSensitive), cancellationToken); diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 2e44682ac8a6a..01e20061a717a 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -37,7 +37,6 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; internal partial class InlineRenameSession : IInlineRenameSession, IFeatureController { - private readonly Workspace _workspace; private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; private readonly ITextBufferAssociatedViewService _textBufferAssociatedViewService; @@ -57,8 +56,6 @@ internal partial class InlineRenameSession : IInlineRenameSession, IFeatureContr private bool _dismissed; private bool _isApplyingEdit; private string _replacementText; - private SymbolRenameOptions _options; - private bool _previewChanges; private readonly Dictionary _openTextBuffers = []; /// @@ -97,13 +94,13 @@ private set /// /// Information about this rename session. /// - public IInlineRenameInfo RenameInfo => _renameInfo; + public IInlineRenameInfo RenameInfo { get; } /// /// The task which computes the main rename locations against the original workspace /// snapshot. /// - public JoinableTask AllRenameLocationsTask => _allRenameLocationsTask; + public JoinableTask AllRenameLocationsTask { get; private set; } /// /// Keep-alive session held alive with the OOP server. This allows us to pin the initial solution snapshot over on @@ -112,20 +109,14 @@ private set /// private readonly RemoteKeepAliveSession _keepAliveSession; - /// - /// The task which computes the main rename locations against the original workspace - /// snapshot. - /// - private JoinableTask _allRenameLocationsTask; - /// /// The cancellation token for most work being done by the inline rename session. This - /// includes the tasks. + /// includes the tasks. /// private readonly CancellationTokenSource _cancellationTokenSource = new(); /// - /// This task is a continuation of the that is the result of computing + /// This task is a continuation of the that is the result of computing /// the resolutions of the rename spans for the current replacementText. /// private JoinableTask _conflictResolutionTask; @@ -133,9 +124,7 @@ private set /// /// The cancellation source for . /// - private CancellationTokenSource _conflictResolutionTaskCancellationSource = new CancellationTokenSource(); - - private readonly IInlineRenameInfo _renameInfo; + private CancellationTokenSource _conflictResolutionTaskCancellationSource = new(); /// /// The initial text being renamed. @@ -160,7 +149,7 @@ public InlineRenameSession( { // This should always be touching a symbol since we verified that upon invocation _threadingContext = threadingContext; - _renameInfo = renameInfo; + RenameInfo = renameInfo; TriggerSpan = triggerSpan; TriggerDocument = triggerSpan.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); @@ -171,8 +160,8 @@ public InlineRenameSession( _inlineRenameSessionDurationLogBlock = Logger.LogBlock(FunctionId.Rename_InlineSession, CancellationToken.None); - _workspace = workspace; - _workspace.WorkspaceChanged += OnWorkspaceChanged; + Workspace = workspace; + Workspace.WorkspaceChanged += OnWorkspaceChanged; _textBufferFactoryService = textBufferFactoryService; _textBufferCloneService = textBufferCloneService; @@ -189,8 +178,8 @@ public InlineRenameSession( _triggerView = textBufferAssociatedViewService.GetAssociatedTextViews(triggerSpan.Snapshot.TextBuffer).FirstOrDefault(v => v.HasAggregateFocus) ?? textBufferAssociatedViewService.GetAssociatedTextViews(triggerSpan.Snapshot.TextBuffer).First(); - _options = options; - _previewChanges = previewChanges; + Options = options; + PreviewChanges = previewChanges; _initialRenameText = triggerSpan.GetText(); this.ReplacementText = _initialRenameText; @@ -198,7 +187,7 @@ public InlineRenameSession( _baseSolution = TriggerDocument.Project.Solution; this.UndoManager = workspace.Services.GetService(); - FileRenameInfo = _renameInfo.GetFileRenameInfo(); + FileRenameInfo = RenameInfo.GetFileRenameInfo(); // Open a session to oop, syncing our solution to it and pinning it there. The connection will close once // _cancellationTokenSource is canceled (which we always do when the session is finally ended). @@ -206,7 +195,7 @@ public InlineRenameSession( InitializeOpenBuffers(triggerSpan); } - public string OriginalSymbolName => _renameInfo.DisplayName; + public string OriginalSymbolName => RenameInfo.DisplayName; // Used to aid the investigation of https://github.com/dotnet/roslyn/issues/7364 private class NullTextBufferException(Document document, SourceText text) : Exception("Cannot retrieve textbuffer from document.") @@ -221,7 +210,7 @@ private void InitializeOpenBuffers(SnapshotSpan triggerSpan) using (Logger.LogBlock(FunctionId.Rename_CreateOpenTextBufferManagerForAllOpenDocs, CancellationToken.None)) { var openBuffers = new HashSet(); - foreach (var d in _workspace.GetOpenDocumentIds()) + foreach (var d in Workspace.GetOpenDocumentIds()) { var document = _baseSolution.GetDocument(d); if (document == null) @@ -266,7 +255,7 @@ private void InitializeOpenBuffers(SnapshotSpan triggerSpan) UpdateReferenceLocationsTask(); - RenameTrackingDismisser.DismissRenameTracking(_workspace, _workspace.GetOpenDocumentIds()); + RenameTrackingDismisser.DismissRenameTracking(Workspace, Workspace.GetOpenDocumentIds()); } private bool TryPopulateOpenTextBufferManagerForBuffer(ITextBuffer buffer) @@ -274,7 +263,7 @@ private bool TryPopulateOpenTextBufferManagerForBuffer(ITextBuffer buffer) _threadingContext.ThrowIfNotOnUIThread(); VerifyNotDismissed(); - if (_workspace.Kind == WorkspaceKind.Interactive) + if (Workspace.Kind == WorkspaceKind.Interactive) { Debug.Assert(buffer.GetRelatedDocuments().Count() == 1); Debug.Assert(buffer.IsReadOnly(0) == buffer.IsReadOnly(VisualStudio.Text.Span.FromBounds(0, buffer.CurrentSnapshot.Length))); // All or nothing. @@ -286,7 +275,7 @@ private bool TryPopulateOpenTextBufferManagerForBuffer(ITextBuffer buffer) if (!_openTextBuffers.ContainsKey(buffer) && buffer.SupportsRename()) { - _openTextBuffers[buffer] = new OpenTextBufferManager(this, _workspace, _textBufferFactoryService, _textBufferCloneService, buffer); + _openTextBuffers[buffer] = new OpenTextBufferManager(this, Workspace, _textBufferFactoryService, _textBufferCloneService, buffer); return true; } @@ -298,7 +287,7 @@ private void OnSubjectBuffersConnected(object sender, SubjectBuffersConnectedEve _threadingContext.ThrowIfNotOnUIThread(); foreach (var buffer in e.SubjectBuffers) { - if (buffer.GetWorkspace() == _workspace) + if (buffer.GetWorkspace() == Workspace) { if (TryPopulateOpenTextBufferManagerForBuffer(buffer)) { @@ -314,19 +303,19 @@ private void UpdateReferenceLocationsTask() var asyncToken = _asyncListener.BeginAsyncOperation("UpdateReferencesTask"); - var currentOptions = _options; - var currentRenameLocationsTask = _allRenameLocationsTask; + var currentOptions = Options; + var currentRenameLocationsTask = AllRenameLocationsTask; var cancellationToken = _cancellationTokenSource.Token; - _allRenameLocationsTask = _threadingContext.JoinableTaskFactory.RunAsync(async () => + AllRenameLocationsTask = _threadingContext.JoinableTaskFactory.RunAsync(async () => { // Join prior work before proceeding, since it performs a required state update. // https://github.com/dotnet/roslyn/pull/34254#discussion_r267024593 if (currentRenameLocationsTask != null) - await _allRenameLocationsTask.JoinAsync(cancellationToken).ConfigureAwait(false); + await AllRenameLocationsTask.JoinAsync(cancellationToken).ConfigureAwait(false); await TaskScheduler.Default; - var inlineRenameLocations = await _renameInfo.FindRenameLocationsAsync(currentOptions, cancellationToken).ConfigureAwait(false); + var inlineRenameLocations = await RenameInfo.FindRenameLocationsAsync(currentOptions, cancellationToken).ConfigureAwait(false); // It's unfortunate that _allRenameLocationsTask has a UI thread dependency (prevents continuations // from running prior to the completion of the UI operation), but the implementation does not currently @@ -339,17 +328,17 @@ private void UpdateReferenceLocationsTask() return inlineRenameLocations; }); - _allRenameLocationsTask.Task.CompletesAsyncOperation(asyncToken); + AllRenameLocationsTask.Task.CompletesAsyncOperation(asyncToken); UpdateConflictResolutionTask(); QueueApplyReplacements(); } - public Workspace Workspace => _workspace; - public SymbolRenameOptions Options => _options; - public bool PreviewChanges => _previewChanges; - public bool HasRenameOverloads => _renameInfo.HasOverloads; - public bool MustRenameOverloads => _renameInfo.MustRenameOverloads; + public Workspace Workspace { get; } + public SymbolRenameOptions Options { get; private set; } + public bool PreviewChanges { get; private set; } + public bool HasRenameOverloads => RenameInfo.HasOverloads; + public bool MustRenameOverloads => RenameInfo.MustRenameOverloads; public IInlineRenameUndoManager UndoManager { get; } @@ -365,7 +354,7 @@ internal bool TryGetBufferManager(ITextBuffer buffer, out OpenTextBufferManager public void RefreshRenameSessionWithOptionsChanged(SymbolRenameOptions newOptions) { - if (_options == newOptions) + if (Options == newOptions) { return; } @@ -373,7 +362,7 @@ public void RefreshRenameSessionWithOptionsChanged(SymbolRenameOptions newOption _threadingContext.ThrowIfNotOnUIThread(); VerifyNotDismissed(); - _options = newOptions; + Options = newOptions; UpdateReferenceLocationsTask(); } @@ -382,7 +371,7 @@ public void SetPreviewChanges(bool value) _threadingContext.ThrowIfNotOnUIThread(); VerifyNotDismissed(); - _previewChanges = value; + PreviewChanges = value; } private void VerifyNotDismissed() @@ -397,12 +386,19 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) { if (args.Kind != WorkspaceChangeKind.DocumentChanged) { - Logger.Log(FunctionId.Rename_InlineSession_Cancel_NonDocumentChangedWorkspaceChange, KeyValueLogMessage.Create(m => + // Make sure only call Cancel() when there is real document changes. + // Sometimes, WorkspaceChangeKind.SolutionChanged might be triggered because of SourceGeneratorVersion get updated. + // We don't want to cancel rename when there is no changed documents. + var changedDocuments = args.NewSolution.GetChangedDocuments(args.OldSolution); + if (changedDocuments.Any()) { - m["Kind"] = Enum.GetName(typeof(WorkspaceChangeKind), args.Kind); - })); + Logger.Log(FunctionId.Rename_InlineSession_Cancel_NonDocumentChangedWorkspaceChange, KeyValueLogMessage.Create(m => + { + m["Kind"] = Enum.GetName(typeof(WorkspaceChangeKind), args.Kind); + })); - Cancel(); + Cancel(); + } } } @@ -416,7 +412,7 @@ private void RaiseSessionSpansUpdated(ImmutableArray locat // inline rename is oblivious to unchangeable documents, we just need to filter out references // in them to avoid displaying them in the UI. // https://github.com/dotnet/roslyn/issues/41242 - if (_workspace.IgnoreUnchangeableDocumentsWhenApplyingChanges) + if (Workspace.IgnoreUnchangeableDocumentsWhenApplyingChanges) { locations = locations.WhereAsArray(l => l.Document.CanApplyChange()); } @@ -456,7 +452,7 @@ internal void ApplyReplacementText(string replacementText, bool propagateEditImm { _threadingContext.ThrowIfNotOnUIThread(); VerifyNotDismissed(); - this.ReplacementText = _renameInfo.GetFinalSymbolName(replacementText); + this.ReplacementText = RenameInfo.GetFinalSymbolName(replacementText); var asyncToken = _asyncListener.BeginAsyncOperation(nameof(ApplyReplacementText)); @@ -533,7 +529,7 @@ private void UpdateConflictResolutionTask() } var replacementText = this.ReplacementText; - var options = _options; + var options = Options; var cancellationToken = _conflictResolutionTaskCancellationSource.Token; var asyncToken = _asyncListener.BeginAsyncOperation(nameof(UpdateConflictResolutionTask)); @@ -546,7 +542,7 @@ private void UpdateConflictResolutionTask() // If cancellation of the conflict resolution task is requested before the rename locations task // completes, we do not need to wait for rename before cancelling. The next conflict resolution task // will wait on the latest rename location task if/when necessary. - var result = await _allRenameLocationsTask.JoinAsync(cancellationToken).ConfigureAwait(false); + var result = await AllRenameLocationsTask.JoinAsync(cancellationToken).ConfigureAwait(false); await TaskScheduler.Default; return await result.GetReplacementsAsync(replacementText, options, cancellationToken).ConfigureAwait(false); @@ -633,7 +629,7 @@ private void LogRenameSession(RenameLogMessage.UserActionOutcome outcome, bool p var replacementKinds = result.GetAllReplacementKinds().ToList(); Logger.Log(FunctionId.Rename_InlineSession_Session, RenameLogMessage.Create( - _options, + Options, outcome, conflictResolutionFinishedComputing, previewChanges, @@ -643,7 +639,7 @@ private void LogRenameSession(RenameLogMessage.UserActionOutcome outcome, bool p { Debug.Assert(outcome.HasFlag(RenameLogMessage.UserActionOutcome.Canceled)); Logger.Log(FunctionId.Rename_InlineSession_Session, RenameLogMessage.Create( - _options, + Options, outcome, conflictResolutionFinishedComputing, previewChanges, @@ -655,26 +651,25 @@ public void Cancel() { _threadingContext.ThrowIfNotOnUIThread(); - // This wait is safe. We are not passing the async callback to DismissUIAndRollbackEditsAndEndRenameSessionAsync. - // So everything in that method will happen synchronously. - DismissUIAndRollbackEditsAndEndRenameSessionAsync( - RenameLogMessage.UserActionOutcome.Canceled, previewChanges: false).Wait(); + DismissUIAndRollbackEditsAndEndRenameSession_MustBeCalledOnUIThread( + RenameLogMessage.UserActionOutcome.Canceled, previewChanges: false); } - private async Task DismissUIAndRollbackEditsAndEndRenameSessionAsync( + /// + /// Dismisses the UI, rolls back any edits, and ends the rename session. + /// + private void DismissUIAndRollbackEditsAndEndRenameSession_MustBeCalledOnUIThread( RenameLogMessage.UserActionOutcome outcome, bool previewChanges, - Func finalCommitAction = null) + Action finalCommitAction = null) { // Note: this entire sequence of steps is not cancellable. We must perform it all to get back to a correct // state for all the editors the user is interacting with. var cancellationToken = CancellationToken.None; - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + _threadingContext.ThrowIfNotOnUIThread(); if (_dismissed) - { return; - } _dismissed = true; @@ -689,17 +684,13 @@ private async Task DismissUIAndRollbackEditsAndEndRenameSessionAsync( _keepAliveSession.Dispose(); // Perform the actual commit step if we've been asked to. - if (finalCommitAction != null) - { - // ConfigureAwait(true) so we come back to the UI thread to finish work. - await finalCommitAction().ConfigureAwait(true); - } + finalCommitAction?.Invoke(); // Log the result so we know how well rename is going in practice. LogRenameSession(outcome, previewChanges); // Remove all our rename trackers from the text buffer properties. - RenameTrackingDismisser.DismissRenameTracking(_workspace, _workspace.GetOpenDocumentIds()); + RenameTrackingDismisser.DismissRenameTracking(Workspace, Workspace.GetOpenDocumentIds()); // Log how long the full rename took. _inlineRenameSessionDurationLogBlock.Dispose(); @@ -708,7 +699,7 @@ private async Task DismissUIAndRollbackEditsAndEndRenameSessionAsync( void DismissUIAndRollbackEdits() { - _workspace.WorkspaceChanged -= OnWorkspaceChanged; + Workspace.WorkspaceChanged -= OnWorkspaceChanged; _textBufferAssociatedViewService.SubjectBuffersConnected -= OnSubjectBuffersConnected; // Reenable completion now that the inline rename session is done @@ -734,29 +725,44 @@ void DismissUIAndRollbackEdits() } } - public void Commit(bool previewChanges = false) - => CommitWorker(previewChanges); + /// + /// Caller should pass in the IUIThreadOperationContext if it is called from editor so rename commit operation could set up the its own context correctly. + /// + public void Commit(bool previewChanges = false, IUIThreadOperationContext editorOperationContext = null) + => CommitSynchronously(previewChanges, editorOperationContext); /// if the rename operation was committed, otherwise - private bool CommitWorker(bool previewChanges) + private bool CommitSynchronously(bool previewChanges, IUIThreadOperationContext operationContext = null) { // We're going to synchronously block the UI thread here. So we can't use the background work indicator (as // it needs the UI thread to update itself. This will force us to go through the Threaded-Wait-Dialog path // which at least will allow the user to cancel the rename if they want. // // In the future we should remove this entrypoint and have all callers use CommitAsync instead. - return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false, CancellationToken.None)); + return _threadingContext.JoinableTaskFactory.Run(() => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: false, operationContext)); } - public Task CommitAsync(bool previewChanges, CancellationToken cancellationToken) - => CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, cancellationToken); + /// + /// Caller should pass in the IUIThreadOperationContext if it is called from editor so rename commit operation could set up the its own context correctly. + /// + public async Task CommitAsync(bool previewChanges, IUIThreadOperationContext editorOperationContext = null) + { + if (this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) + { + await CommitWorkerAsync(previewChanges, canUseBackgroundWorkIndicator: true, editorOperationContext).ConfigureAwait(false); + } + else + { + CommitSynchronously(previewChanges, editorOperationContext); + } + } - /// if the rename operation was commited, if the rename operation was committed, otherwise - private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackgroundWorkIndicator, CancellationToken cancellationToken) + private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackgroundWorkIndicator, IUIThreadOperationContext editorUIOperationContext) { - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); VerifyNotDismissed(); // If the identifier was deleted (or didn't change at all) then cancel the operation. @@ -775,18 +781,25 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg return false; } - previewChanges = previewChanges || _previewChanges; + previewChanges = previewChanges || PreviewChanges; + + if (editorUIOperationContext is not null) + { + // Prevent Editor's typing responsiveness auto canceling the rename operation. + // InlineRenameSession will call IUIThreadOperationExecutor to sets up our own IUIThreadOperationContext + editorUIOperationContext.TakeOwnership(); + } try { - if (canUseBackgroundWorkIndicator && this.RenameService.GlobalOptions.GetOption(InlineRenameSessionOptionsStorage.RenameAsynchronously)) + if (canUseBackgroundWorkIndicator) { // We do not cancel on edit because as part of the rename system we have asynchronous work still // occurring that itself may be asynchronously editing the buffer (for example, updating reference // locations with the final renamed text). Ideally though, once we start comitting, we would cancel // any of that work and then only have the work of rolling back to the original state of the world // and applying the desired edits ourselves. - var factory = _workspace.Services.GetRequiredService(); + var factory = Workspace.Services.GetRequiredService(); using var context = factory.Create( _triggerView, TriggerSpan, EditorFeaturesResources.Computing_Rename_information, cancelOnEdit: false, cancelOnFocusLost: false); @@ -809,8 +822,9 @@ private async Task CommitWorkerAsync(bool previewChanges, bool canUseBackg } catch (OperationCanceledException) { - await DismissUIAndRollbackEditsAndEndRenameSessionAsync( - RenameLogMessage.UserActionOutcome.Canceled | RenameLogMessage.UserActionOutcome.Committed, previewChanges).ConfigureAwait(false); + // We've used CA(true) consistently in this method. So we should always be on the UI thread. + DismissUIAndRollbackEditsAndEndRenameSession_MustBeCalledOnUIThread( + RenameLogMessage.UserActionOutcome.Canceled | RenameLogMessage.UserActionOutcome.Committed, previewChanges); return false; } @@ -828,7 +842,7 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b if (previewChanges) { - var previewService = _workspace.Services.GetService(); + var previewService = Workspace.Services.GetService(); // The preview service needs to be called from the UI thread, since it's doing COM calls underneath. await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); @@ -836,8 +850,8 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename), "vs.csharp.refactoring.rename", string.Format(EditorFeaturesResources.Rename_0_to_1_colon, this.OriginalSymbolName, this.ReplacementText), - _renameInfo.FullDisplayName, - _renameInfo.Glyph, + RenameInfo.FullDisplayName, + RenameInfo.Glyph, newSolution, TriggerDocument.Project.Solution); @@ -849,70 +863,102 @@ private async Task CommitCoreAsync(IUIThreadOperationContext operationContext, b } // The user hasn't canceled by now, so we're done waiting for them. Off to rename! - using var _ = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files); + using var _1 = operationContext.AddScope(allowCancellation: true, EditorFeaturesResources.Updating_files); + + await TaskScheduler.Default; - await DismissUIAndRollbackEditsAndEndRenameSessionAsync( + // While on the background, attempt to figure out the actual changes to make to the workspace's current solution. + var documentChanges = await CalculateFinalDocumentChangesAsync(newSolution, cancellationToken).ConfigureAwait(false); + + // Now jump back to the UI thread to actually apply those changes. + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + // We're about to make irrevocable changes to the workspace and UI. We're no longer cancellable at this point. + using var _2 = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files); + cancellationToken = CancellationToken.None; + + // Dismiss the rename UI and rollback any linked edits made. + DismissUIAndRollbackEditsAndEndRenameSession_MustBeCalledOnUIThread( RenameLogMessage.UserActionOutcome.Committed, previewChanges, - async () => + () => { - var error = await TryApplyRenameAsync(newSolution, cancellationToken).ConfigureAwait(false); - + // Now try to apply that change we computed to the workspace. + var error = TryApplyRename(documentChanges); if (error is not null) { - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - var notificationService = _workspace.Services.GetService(); + var notificationService = Workspace.Services.GetService(); notificationService.SendNotification( error.Value.message, EditorFeaturesResources.Rename_Symbol, error.Value.severity); } - }).ConfigureAwait(false); + }); } - } - /// - /// Returns non-null error message if renaming fails. - /// - private async Task<(NotificationSeverity severity, string message)?> TryApplyRenameAsync( - Solution newSolution, CancellationToken cancellationToken) - { - var changes = _baseSolution.GetChanges(newSolution); - var changedDocumentIDs = changes.GetProjectChanges().SelectMany(c => c.GetChangedDocuments()).ToList(); + async Task> CalculateFinalDocumentChangesAsync( + Solution newSolution, CancellationToken cancellationToken) + { + var changes = _baseSolution.GetChanges(newSolution); + var changedDocumentIDs = changes.GetProjectChanges().SelectManyAsArray(c => c.GetChangedDocuments()); - // Go to the background thread for initial calculation of the final solution - await TaskScheduler.Default; - var finalSolution = CalculateFinalSolutionSynchronously(newSolution, newSolution.Workspace, changedDocumentIDs, cancellationToken); + using var _ = PooledObjects.ArrayBuilder<(DocumentId documentId, string newName, SyntaxNode newRoot, SourceText newText)>.GetInstance(out var result); - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + foreach (var documentId in changes.GetProjectChanges().SelectMany(c => c.GetChangedDocuments())) + { + // If the document supports syntax tree, then create the new solution from the updated syntax root. + // This should ensure that annotations are preserved, and prevents the solution from having to reparse + // documents when we already have the trees for them. If we don't support syntax, then just use the + // text of the document. + var newDocument = newSolution.GetDocument(documentId); + + result.Add(newDocument.SupportsSyntaxTree + ? (documentId, newDocument.Name, await newDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false), newText: null) + : (documentId, newDocument.Name, newRoot: null, await newDocument.GetTextAsync(cancellationToken).ConfigureAwait(false))); + } - using var undoTransaction = _workspace.OpenGlobalUndoTransaction(EditorFeaturesResources.Inline_Rename); + return result.ToImmutableAndClear(); + } + } - if (!_renameInfo.TryOnBeforeGlobalSymbolRenamed(_workspace, changedDocumentIDs, this.ReplacementText)) + // Returns non-null error message if renaming fails. + private (NotificationSeverity severity, string message)? TryApplyRename( + ImmutableArray<(DocumentId documentId, string newName, SyntaxNode newRoot, SourceText newText)> documentChanges) + { + _threadingContext.ThrowIfNotOnUIThread(); + + using var undoTransaction = Workspace.OpenGlobalUndoTransaction(EditorFeaturesResources.Inline_Rename); + + if (!RenameInfo.TryOnBeforeGlobalSymbolRenamed(Workspace, documentChanges.SelectAsArray(t => t.documentId), this.ReplacementText)) return (NotificationSeverity.Error, EditorFeaturesResources.Rename_operation_was_cancelled_or_is_not_valid); - if (!_workspace.TryApplyChanges(finalSolution)) + // Grab the workspace's current solution, and make the document changes to it we computed. + var finalSolution = Workspace.CurrentSolution; + foreach (var (documentId, newName, newRoot, newText) in documentChanges) { - // If the workspace changed in TryOnBeforeGlobalSymbolRenamed retry, this prevents rename from failing for cases - // where text changes to other files or workspace state change doesn't impact the text changes being applied. - Logger.Log(FunctionId.Rename_TryApplyRename_WorkspaceChanged, message: null, LogLevel.Information); - finalSolution = CalculateFinalSolutionSynchronously(newSolution, _workspace, changedDocumentIDs, cancellationToken); + finalSolution = newRoot != null + ? finalSolution.WithDocumentSyntaxRoot(documentId, newRoot) + : finalSolution.WithDocumentText(documentId, newText); - if (!_workspace.TryApplyChanges(finalSolution)) - return (NotificationSeverity.Error, EditorFeaturesResources.Rename_operation_could_not_complete_due_to_external_change_to_workspace); + finalSolution = finalSolution.WithDocumentName(documentId, newName); } + // Now actually go and apply the changes to the workspace. We expect this to succeed as we're on the UI + // thread, and nothing else should have been able to make a change to workspace since we we grabbed its + // current solution and forked it. + if (!Workspace.TryApplyChanges(finalSolution)) + return (NotificationSeverity.Error, EditorFeaturesResources.Rename_operation_could_not_complete_due_to_external_change_to_workspace); + try { // Since rename can apply file changes as well, and those file // changes can generate new document ids, include added documents // as well as changed documents. This also ensures that any document // that was removed is not included - var finalChanges = _workspace.CurrentSolution.GetChanges(_baseSolution); + var finalChanges = Workspace.CurrentSolution.GetChanges(_baseSolution); var finalChangedIds = finalChanges .GetProjectChanges() - .SelectMany(c => c.GetChangedDocuments().Concat(c.GetAddedDocuments())) - .ToList(); + .SelectManyAsArray(c => c.GetChangedDocuments().Concat(c.GetAddedDocuments())); - if (!_renameInfo.TryOnAfterGlobalSymbolRenamed(_workspace, finalChangedIds, this.ReplacementText)) + if (!RenameInfo.TryOnAfterGlobalSymbolRenamed(Workspace, finalChangedIds, this.ReplacementText)) return (NotificationSeverity.Information, EditorFeaturesResources.Rename_operation_was_not_properly_completed_Some_file_might_not_have_been_updated); return null; @@ -923,36 +969,6 @@ await DismissUIAndRollbackEditsAndEndRenameSessionAsync( // always able to undo anything any other external listener did. undoTransaction.Commit(); } - - static Solution CalculateFinalSolutionSynchronously(Solution newSolution, Workspace workspace, List changedDocumentIDs, CancellationToken cancellationToken) - { - var finalSolution = workspace.CurrentSolution; - foreach (var id in changedDocumentIDs) - { - // If the document supports syntax tree, then create the new solution from the - // updated syntax root. This should ensure that annotations are preserved, and - // prevents the solution from having to reparse documents when we already have - // the trees for them. If we don't support syntax, then just use the text of - // the document. - var newDocument = newSolution.GetDocument(id); - - if (newDocument.SupportsSyntaxTree) - { - var root = newDocument.GetRequiredSyntaxRootSynchronously(cancellationToken); - finalSolution = finalSolution.WithDocumentSyntaxRoot(id, root); - } - else - { - var newText = newDocument.GetTextSynchronously(cancellationToken); - finalSolution = finalSolution.WithDocumentText(id, newText); - } - - // Make sure to include any document rename as well - finalSolution = finalSolution.WithDocumentName(id, newDocument.Name); - } - - return finalSolution; - } } internal bool TryGetContainingEditableSpan(SnapshotPoint point, out SnapshotSpan editableSpan) @@ -986,6 +1002,6 @@ public readonly struct TestAccessor(InlineRenameSession inlineRenameSession) private readonly InlineRenameSession _inlineRenameSession = inlineRenameSession; public bool CommitWorker(bool previewChanges) - => _inlineRenameSession.CommitWorker(previewChanges); + => _inlineRenameSession.CommitSynchronously(previewChanges); } } diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/FilterSet.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/FilterSet.cs index 6477cfdd23667..817c456bf6c85 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/FilterSet.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/FilterSet.cs @@ -131,7 +131,7 @@ private static CompletionFilter CreateCompletionFilter( public (ImmutableArray filters, int data) GetFiltersAndAddToSet(RoslynCompletionItem item) { - var listBuilder = new ArrayBuilder(); + using var _ = ArrayBuilder.GetInstance(out var listBuilder); var vectorForSingleItem = new BitVector32(); if (item.Flags.IsExpanded()) @@ -150,7 +150,7 @@ private static CompletionFilter CreateCompletionFilter( } } - return (listBuilder.ToImmutableAndFree(), vectorForSingleItem.Data); + return (listBuilder.ToImmutableAndClear(), vectorForSingleItem.Data); } // test only diff --git a/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs b/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs index fe1dbd36b0627..8bd7fe294313c 100644 --- a/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs +++ b/src/EditorFeatures/Core/LanguageServer/AlwaysActivateInProcLanguageClient.cs @@ -69,6 +69,10 @@ public override ServerCapabilities GetCapabilities(ClientCapabilities clientCapa serverCapabilities.BreakableRangeProvider = true; serverCapabilities.SupportsDiagnosticRequests = true; + + var diagnosticOptions = (serverCapabilities.DiagnosticOptions ??= new DiagnosticOptions()); + diagnosticOptions.Unify().WorkspaceDiagnostics = true; + serverCapabilities.DiagnosticProvider ??= new(); // VS does not distinguish between document and workspace diagnostics, so we need to merge them. diff --git a/src/EditorFeatures/Core/LanguageServer/EditorLspSymbolInformationCreationService.cs b/src/EditorFeatures/Core/LanguageServer/EditorLspSymbolInformationCreationService.cs index 63396a1ff96c5..a167a45407070 100644 --- a/src/EditorFeatures/Core/LanguageServer/EditorLspSymbolInformationCreationService.cs +++ b/src/EditorFeatures/Core/LanguageServer/EditorLspSymbolInformationCreationService.cs @@ -24,6 +24,7 @@ public EditorLspSymbolInformationCreationService() public SymbolInformation Create(string name, string? containerName, LSP.SymbolKind kind, LSP.Location location, Glyph glyph) { var imageId = glyph.GetImageId(); +#pragma warning disable CS0618 // SymbolInformation is obsolete, need to switch to DocumentSymbol/WorkspaceSymbol return new VSSymbolInformation { Name = name, @@ -32,5 +33,6 @@ public SymbolInformation Create(string name, string? containerName, LSP.SymbolKi Location = location, Icon = new VSImageId { Guid = imageId.Guid, Id = imageId.Id }, }; +#pragma warning restore CS0618 } } diff --git a/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs b/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs index f8824504bd507..f988ab4ffc1d4 100644 --- a/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs +++ b/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs @@ -24,6 +24,8 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.NavigationBar; +using LastPresentedInfo = (ImmutableArray projectItems, NavigationBarProjectItem? selectedProjectItem, NavigationBarModel? model, NavigationBarSelectedTypeAndMember selectedInfo); + /// /// The controller for navigation bars. /// @@ -47,7 +49,7 @@ internal partial class NavigationBarController : IDisposable /// skip doing that as the UI will already know about this. This is only ever read or written from . So we don't need to worry about any synchronization over it. /// - private (ImmutableArray projectItems, NavigationBarProjectItem? selectedProjectItem, NavigationBarModel? model, NavigationBarSelectedTypeAndMember selectedInfo) _lastPresentedInfo; + private LastPresentedInfo _lastPresentedInfo; /// /// Source of events that should cause us to update the nav bar model with new information. diff --git a/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs b/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs index 7f8f55fee5d26..340b1de7b482b 100644 --- a/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs +++ b/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs @@ -159,6 +159,11 @@ private async ValueTask SelectItemAsync(ImmutableSegmentedList positions, C return; var model = await modelTask.ConfigureAwait(false); + + // If we didn't get a new model (which can happen if the work to do it was canceled), use the last one we + // computed. This ensures that we still update the project info if needed, and we don't unintentionally + // clear our the type/member info from the last time we computed it. + model ??= lastPresentedInfo.model; var currentSelectedItem = ComputeSelectedTypeAndMember(model, lastCaretPosition, cancellationToken); var (projectItems, selectedProjectItem) = GetProjectItems(); diff --git a/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs b/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs index a119ec7c5ab9e..e884b3129b9c7 100644 --- a/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs +++ b/src/EditorFeatures/Core/Organizing/OrganizeDocumentCommandHandler.cs @@ -191,7 +191,7 @@ public bool ExecuteCommand(SortAndRemoveUnnecessaryImportsCommandArgs args, Comm var removeImportsService = document.GetRequiredLanguageService(); var organizeImportsService = document.GetRequiredLanguageService(); - var newDocument = await removeImportsService.RemoveUnnecessaryImportsAsync(document, formattingOptions, cancellationToken).ConfigureAwait(false); + var newDocument = await removeImportsService.RemoveUnnecessaryImportsAsync(document, cancellationToken).ConfigureAwait(false); var options = await document.GetOrganizeImportsOptionsAsync(cancellationToken).ConfigureAwait(false); return await organizeImportsService.OrganizeImportsAsync(newDocument, options, cancellationToken).ConfigureAwait(false); }); diff --git a/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs b/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs index 44e9ec5626c7a..7021b039a64e1 100644 --- a/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs +++ b/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs @@ -654,8 +654,11 @@ private async ValueTask CreateTextBufferCoreAsync(TextDocument docu var buffer = _textBufferCloneService.Clone(text, contentType); - // Associate buffer with a text document with random file path to satisfy extensibility points expecting absolute file path. - _textDocumentFactoryService.CreateTextDocument(buffer, Path.GetTempFileName()); + // Associate buffer with a text document with random file path to satisfy extensibility points expecting + // absolute file path. Ensure the new path preserves the same extension as before as that extension is used by + // LSP to determine the language of the document. + _textDocumentFactoryService.CreateTextDocument( + buffer, Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString(), document.Name)); return buffer; } diff --git a/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs b/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs index d0b1146c9362b..9c288cc54b153 100644 --- a/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs +++ b/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs @@ -164,6 +164,11 @@ private void OnActiveDocumentChanged(object? sender, DocumentId? e) private async ValueTask SynchronizePrimaryWorkspaceAsync(CancellationToken cancellationToken) { var solution = _workspace.CurrentSolution; + + // Wait for the remote side to actually become available (without being the cause of its creation ourselves). We + // want to wait for some feature to kick this off, then we'll start syncing this data once that has happened. + await RemoteHostClient.WaitForClientCreationAsync(_workspace, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false); if (client == null) return; @@ -181,6 +186,10 @@ private async ValueTask SynchronizeActiveDocumentAsync(CancellationToken cancell { var activeDocument = _documentTrackingService.TryGetActiveDocument(); + // Wait for the remote side to actually become available (without being the cause of its creation ourselves). We + // want to wait for some feature to kick this off, then we'll start syncing this data once that has happened. + await RemoteHostClient.WaitForClientCreationAsync(_workspace, cancellationToken).ConfigureAwait(false); + var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false); if (client == null) return; diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs index 1bf2cf11cc79a..af17f723ee661 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs @@ -38,7 +38,6 @@ private sealed class StateMachine private readonly IInlineRenameService _inlineRenameService; private readonly IAsynchronousOperationListener _asyncListener; - private readonly ITextBuffer _buffer; private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService; // Store committed sessions so they can be restored on undo/redo. The undo transactions @@ -50,7 +49,7 @@ private sealed class StateMachine public readonly IGlobalOptionService GlobalOptions; public TrackingSession TrackingSession { get; private set; } - public ITextBuffer Buffer => _buffer; + public ITextBuffer Buffer { get; } public event Action TrackingSessionUpdated = delegate { }; public event Action TrackingSessionCleared = delegate { }; @@ -64,8 +63,8 @@ public StateMachine( IAsynchronousOperationListener asyncListener) { ThreadingContext = threadingContext; - _buffer = buffer; - _buffer.Changed += Buffer_Changed; + Buffer = buffer; + Buffer.Changed += Buffer_Changed; _inlineRenameService = inlineRenameService; _asyncListener = asyncListener; _diagnosticAnalyzerService = diagnosticAnalyzerService; @@ -132,7 +131,7 @@ public void UpdateTrackingSessionIfRenamable() ThreadingContext.ThrowIfNotOnUIThread(); if (this.TrackingSession.IsDefinitelyRenamableIdentifier()) { - this.TrackingSession.CheckNewIdentifier(this, _buffer.CurrentSnapshot); + this.TrackingSession.CheckNewIdentifier(this, Buffer.CurrentSnapshot); TrackingSessionUpdated(); } } @@ -232,7 +231,7 @@ public bool ClearVisibleTrackingSession() if (this.TrackingSession != null && this.TrackingSession.IsDefinitelyRenamableIdentifier()) { - var document = _buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + var document = Buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) { // When rename tracking is dismissed via escape, we no longer wish to @@ -349,7 +348,7 @@ private bool TryGetSyntaxFactsService(out ISyntaxFactsService syntaxFactsService // Can be called on a background thread syntaxFactsService = null; - var document = _buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + var document = Buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) { syntaxFactsService = document.GetLanguageService(); @@ -363,7 +362,7 @@ private bool TryGetLanguageHeuristicsService(out IRenameTrackingLanguageHeuristi // Can be called on a background thread languageHeuristicsService = null; - var document = _buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); + var document = Buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) { languageHeuristicsService = document.GetLanguageService(); diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs index 8808d2f170695..3ec77331b758d 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs @@ -45,14 +45,11 @@ private class TrackingSession private Task _newIdentifierBindsTask = SpecializedTasks.False; - private readonly string _originalName; - public string OriginalName => _originalName; + public string OriginalName { get; } - private readonly ITrackingSpan _trackingSpan; - public ITrackingSpan TrackingSpan => _trackingSpan; + public ITrackingSpan TrackingSpan { get; } - private bool _forceRenameOverloads; - public bool ForceRenameOverloads => _forceRenameOverloads; + public bool ForceRenameOverloads { get; private set; } public TrackingSession( StateMachine stateMachine, @@ -61,7 +58,7 @@ public TrackingSession( { _threadingContext = stateMachine.ThreadingContext; _asyncListener = asyncListener; - _trackingSpan = snapshotSpan.Snapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeInclusive); + TrackingSpan = snapshotSpan.Snapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeInclusive); _cancellationToken = _cancellationTokenSource.Token; if (snapshotSpan.Length > 0) @@ -71,7 +68,7 @@ public TrackingSession( // renameable identifier. If it is, alert the state machine so it can trigger // tagging. - _originalName = snapshotSpan.GetText(); + OriginalName = snapshotSpan.GetText(); _isRenamableIdentifierTask = Task.Factory.SafeStartNewFromAsync( () => DetermineIfRenamableIdentifierAsync(snapshotSpan, initialCheck: true), _cancellationToken, @@ -194,7 +191,7 @@ private async Task DetermineIfRenamableIdentifierAsync(Sn if (renameSymbolInfo.IsMemberGroup) { // This is a reference from a nameof expression. Allow the rename but set the RenameOverloads option - _forceRenameOverloads = true; + ForceRenameOverloads = true; return await DetermineIfRenamableSymbolsAsync(renameSymbolInfo.Symbols, document).ConfigureAwait(false); } diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.UndoPrimitive.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.UndoPrimitive.cs index 29de67751f109..fdff102a12838 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.UndoPrimitive.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.UndoPrimitive.cs @@ -25,12 +25,7 @@ private class UndoPrimitive(ITextBuffer textBuffer, int trackingSessionId, bool private readonly int _trackingSessionId = trackingSessionId; private readonly bool _shouldRestoreStateOnUndo = shouldRestoreStateOnUndo; - private ITextUndoTransaction _parent; - public ITextUndoTransaction Parent - { - get { return _parent; } - set { _parent = value; } - } + public ITextUndoTransaction Parent { get; set; } public bool CanRedo => true; diff --git a/src/EditorFeatures/Core/Shared/Extensions/IBufferGraphExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/IBufferGraphExtensions.cs index f99d5be3083c6..aa52f98f9cf58 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/IBufferGraphExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/IBufferGraphExtensions.cs @@ -22,12 +22,12 @@ internal static class IBufferGraphExtensions public static SnapshotSpan? MapUpOrDownToFirstMatch(this IBufferGraph bufferGraph, SnapshotSpan span, Predicate match) { var spans = bufferGraph.MapDownToFirstMatch(span, SpanTrackingMode.EdgeExclusive, match); - if (!spans.Any()) + if (spans.Count == 0) { spans = bufferGraph.MapUpToFirstMatch(span, SpanTrackingMode.EdgeExclusive, match); } - return spans.Select(s => (SnapshotSpan?)s).FirstOrDefault(); + return spans.Count > 0 ? spans[0] : null; } public static SnapshotSpan? MapUpOrDownToBuffer(this IBufferGraph bufferGraph, SnapshotSpan span, ITextBuffer targetBuffer) @@ -41,13 +41,13 @@ internal static class IBufferGraphExtensions case BufferMapDirection.Down: { var spans = bufferGraph.MapDownToBuffer(span, SpanTrackingMode.EdgeExclusive, targetBuffer); - return spans.Select(s => (SnapshotSpan?)s).FirstOrDefault(); + return spans.Count > 0 ? spans[0] : null; } case BufferMapDirection.Up: { var spans = bufferGraph.MapUpToBuffer(span, SpanTrackingMode.EdgeExclusive, targetBuffer); - return spans.Select(s => (SnapshotSpan?)s).FirstOrDefault(); + return spans.Count > 0 ? spans[0] : null; } default: diff --git a/src/EditorFeatures/Core/Shared/Utilities/IUIContextActivationService.cs b/src/EditorFeatures/Core/Shared/Utilities/IUIContextActivationService.cs index a68e544abd1b4..2b93cdb11512c 100644 --- a/src/EditorFeatures/Core/Shared/Utilities/IUIContextActivationService.cs +++ b/src/EditorFeatures/Core/Shared/Utilities/IUIContextActivationService.cs @@ -11,5 +11,5 @@ internal interface IUIContextActivationService /// /// Executes the specified action when the UIContext first becomes active, or immediately if it is already active /// - void ExecuteWhenActivated(Guid uiContext, Action action); + IDisposable ExecuteWhenActivated(Guid uiContext, Action action); } diff --git a/src/EditorFeatures/Core/Shared/Utilities/VirtualTreePoint.cs b/src/EditorFeatures/Core/Shared/Utilities/VirtualTreePoint.cs index 3a14bf4ea750b..20cc5c24cf22e 100644 --- a/src/EditorFeatures/Core/Shared/Utilities/VirtualTreePoint.cs +++ b/src/EditorFeatures/Core/Shared/Utilities/VirtualTreePoint.cs @@ -11,21 +11,16 @@ namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities; internal readonly record struct VirtualTreePoint : IComparable { - private readonly SyntaxTree _tree; - private readonly SourceText _text; - private readonly int _position; - private readonly int _virtualSpaces; - public VirtualTreePoint(SyntaxTree tree, SourceText text, int position, int virtualSpaces = 0) { Contract.ThrowIfNull(tree); Contract.ThrowIfFalse(position >= 0 && position <= tree.Length); Contract.ThrowIfFalse(virtualSpaces >= 0); - _tree = tree; - _text = text; - _position = position; - _virtualSpaces = virtualSpaces; + Tree = tree; + Text = text; + Position = position; + VirtualSpaces = virtualSpaces; } public static bool operator <(VirtualTreePoint left, VirtualTreePoint right) @@ -42,16 +37,16 @@ public VirtualTreePoint(SyntaxTree tree, SourceText text, int position, int virt public bool IsInVirtualSpace { - get { return _virtualSpaces != 0; } + get { return VirtualSpaces != 0; } } - public int Position => _position; + public int Position { get; } - public int VirtualSpaces => _virtualSpaces; + public int VirtualSpaces { get; } - public SourceText Text => _text; + public SourceText Text { get; } - public SyntaxTree Tree => _tree; + public SyntaxTree Tree { get; } public int CompareTo(VirtualTreePoint other) { diff --git a/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs b/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs index 0244ed956c537..aa3ae21b762d3 100644 --- a/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs +++ b/src/EditorFeatures/Core/Structure/AbstractStructureTaggerProvider.cs @@ -206,9 +206,13 @@ private void ProcessSpans( ImmutableArray spans) { var snapshot = snapshotSpan.Snapshot; - spans = GetMultiLineRegions(outliningService, spans, snapshot); - foreach (var span in spans) + // Use the returned enumerable directly instead of allocating into an array. The returned + // enumeration can contain a fairly large number of items for large files, so even + // using an ArrayBuilder could result in allocation issues without using a custom pool. + var multiLineSpans = GetMultiLineRegions(outliningService, spans, snapshot); + + foreach (var span in multiLineSpans) { var tag = new StructureTag(this, span, snapshot); context.AddTag(new TagSpan(span.TextSpan.ToSnapshotSpan(snapshot), tag)); @@ -226,12 +230,11 @@ protected override bool TagEquals(IContainerStructureTag tag1, IContainerStructu private static bool s_exceptionReported = false; - private static ImmutableArray GetMultiLineRegions( + private static IEnumerable GetMultiLineRegions( BlockStructureService service, ImmutableArray regions, ITextSnapshot snapshot) { // Remove any spans that aren't multiline. - var multiLineRegions = ArrayBuilder.GetInstance(); foreach (var region in regions) { if (region.TextSpan.Length > 0) @@ -262,12 +265,10 @@ private static ImmutableArray GetMultiLineRegions( var endLine = snapshot.GetLineNumberFromPosition(region.TextSpan.End); if (startLine != endLine) { - multiLineRegions.Add(region); + yield return region; } } } - - return multiLineRegions.ToImmutableAndFree(); } #region Creating Preview Buffers diff --git a/src/EditorFeatures/Core/Workspaces/VSAnalyzerAssemblyLoaderProvider.cs b/src/EditorFeatures/Core/Workspaces/VSAnalyzerAssemblyLoaderProvider.cs deleted file mode 100644 index 9f07b891ffe85..0000000000000 --- a/src/EditorFeatures/Core/Workspaces/VSAnalyzerAssemblyLoaderProvider.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 System.Collections.Generic; -using System.Composition; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; - -namespace Microsoft.CodeAnalysis.Workspaces; - -[ExportWorkspaceService(typeof(IAnalyzerAssemblyLoaderProvider), [WorkspaceKind.Host]), Shared] -internal class VSAnalyzerAssemblyLoaderProvider : AbstractAnalyzerAssemblyLoaderProvider -{ - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VSAnalyzerAssemblyLoaderProvider([ImportMany] IEnumerable externalResolvers) : base(externalResolvers) - { - } -} diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs index 986ae5ba96667..d9c4f5743c053 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs @@ -61,7 +61,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 (ImmutableArray.Empty, null); @@ -71,7 +71,6 @@ protected abstract CodeRefactoringProvider CreateCodeRefactoringProvider( private static async Task GetFixAllFixAsync( CodeAction originalCodeAction, CodeRefactoringProvider provider, - CodeActionOptionsProvider optionsProvider, Document document, TextSpan selectionSpan, FixAllScope scope) @@ -80,7 +79,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); } @@ -105,13 +104,9 @@ internal async Task GetCodeRefactoringAsync( var actions = ArrayBuilder<(CodeAction, TextSpan?)>.GetInstance(); - var codeActionOptionsProvider = parameters.globalOptions?.IsEmpty() == false - ? CodeActionOptionsStorage.GetCodeActionOptionsProvider(workspace.GlobalOptions) - : 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; actions.Free(); return result; } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs index ce53456df18be..97d2aee076071 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs @@ -163,7 +163,6 @@ protected static Document GetDocumentAndSelectSpan(EditorTestWorkspace workspace 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(EditorTestWorkspace workspace 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/EditorFeatures/ExternalAccess/Copilot/Internal/RelatedDocuments/CSharpCopilotRelatedDocumentsService.cs b/src/EditorFeatures/ExternalAccess/Copilot/Internal/RelatedDocuments/CSharpCopilotRelatedDocumentsService.cs new file mode 100644 index 0000000000000..998469fd4923f --- /dev/null +++ b/src/EditorFeatures/ExternalAccess/Copilot/Internal/RelatedDocuments/CSharpCopilotRelatedDocumentsService.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.Collections.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ExternalAccess.Copilot.RelatedDocuments; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.RelatedDocuments; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.RelatedDocuments; + +[ExportLanguageService(typeof(ICopilotRelatedDocumentsService), language: LanguageNames.CSharp), Shared] +internal sealed class CSharpCopilotRelatedDocumentsService : ICopilotRelatedDocumentsService +{ + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpCopilotRelatedDocumentsService() + { + } + + public ValueTask GetRelatedDocumentIdsAsync(Document document, int position, Func, CancellationToken, ValueTask> callbackAsync, CancellationToken cancellationToken) + { + var service = document.GetRequiredLanguageService(); + return service.GetRelatedDocumentIdsAsync(document, position, callbackAsync, cancellationToken); + } +} diff --git a/src/EditorFeatures/ExternalAccess/Copilot/InternalAPI.Unshipped.txt b/src/EditorFeatures/ExternalAccess/Copilot/InternalAPI.Unshipped.txt index 083981a184cff..62074d860791e 100644 --- a/src/EditorFeatures/ExternalAccess/Copilot/InternalAPI.Unshipped.txt +++ b/src/EditorFeatures/ExternalAccess/Copilot/InternalAPI.Unshipped.txt @@ -12,6 +12,8 @@ Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysis Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.IsAnyExclusionAsync(System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.IsAvailableAsync(System.Threading.CancellationToken cancellation) -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.StartRefinementSessionAsync(Microsoft.CodeAnalysis.Document! oldDocument, Microsoft.CodeAnalysis.Document! newDocument, Microsoft.CodeAnalysis.Diagnostic? primaryDiagnostic, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.Copilot.RelatedDocuments.ICopilotRelatedDocumentsService +Microsoft.CodeAnalysis.ExternalAccess.Copilot.RelatedDocuments.ICopilotRelatedDocumentsService.GetRelatedDocumentIdsAsync(Microsoft.CodeAnalysis.Document! document, int position, System.Func, System.Threading.CancellationToken, System.Threading.Tasks.ValueTask>! callbackAsync, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask override Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.Equals(object? obj) -> bool override Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.GetHashCode() -> int static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.Create(System.Collections.Immutable.ImmutableArray values) -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper! diff --git a/src/EditorFeatures/ExternalAccess/Copilot/RelatedDocuments/ICopilotRelatedDocumentsService.cs b/src/EditorFeatures/ExternalAccess/Copilot/RelatedDocuments/ICopilotRelatedDocumentsService.cs new file mode 100644 index 0000000000000..78c8eb5195118 --- /dev/null +++ b/src/EditorFeatures/ExternalAccess/Copilot/RelatedDocuments/ICopilotRelatedDocumentsService.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.RelatedDocuments; + +internal interface ICopilotRelatedDocumentsService : ILanguageService +{ + ValueTask GetRelatedDocumentIdsAsync( + Document document, int position, Func, CancellationToken, ValueTask> callbackAsync, CancellationToken cancellationToken); +} diff --git a/src/EditorFeatures/ExternalAccess/Debugger/GlassTestsHotReloadService.cs b/src/EditorFeatures/ExternalAccess/Debugger/GlassTestsHotReloadService.cs index 21851cf0fd259..891067cc79258 100644 --- a/src/EditorFeatures/ExternalAccess/Debugger/GlassTestsHotReloadService.cs +++ b/src/EditorFeatures/ExternalAccess/Debugger/GlassTestsHotReloadService.cs @@ -84,9 +84,8 @@ public void EndDebuggingSession() public async ValueTask GetUpdatesAsync(Solution solution, CancellationToken cancellationToken) { - var result = await _encService.EmitSolutionUpdateAsync(GetSessionId(), solution, s_noActiveStatementSpanProvider, cancellationToken).ConfigureAwait(false); - var diagnostics = await EmitSolutionUpdateResults.GetAllDiagnosticsAsync(solution, result.Diagnostics.ToDiagnosticData(solution), result.RudeEdits, result.GetSyntaxErrorData(solution), result.ModuleUpdates.Status, cancellationToken).ConfigureAwait(false); - return new ManagedHotReloadUpdates(result.ModuleUpdates.Updates.FromContract(), diagnostics.FromContract()); + var results = (await _encService.EmitSolutionUpdateAsync(GetSessionId(), solution, s_noActiveStatementSpanProvider, cancellationToken).ConfigureAwait(false)).Dehydrate(); + return new ManagedHotReloadUpdates(results.ModuleUpdates.Updates.FromContract(), results.GetAllDiagnostics().FromContract()); } } } diff --git a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs index a59f6172401b1..9c6350aac0bc6 100644 --- a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs +++ b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs @@ -46,7 +46,7 @@ public async Task TestGetFirstDiagnosticWithFixAsync() var diagnosticService = Assert.IsType(workspace.GetService()); var analyzerReference = new TestAnalyzerReferenceByLanguage(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap()); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var logger = SpecializedCollections.SingletonEnumerable(new Lazy(() => workspace.Services.GetRequiredService())); var fixService = new CodeFixService( @@ -56,7 +56,7 @@ public async Task TestGetFirstDiagnosticWithFixAsync() var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); var document = project.Documents.Single(); var unused = await fixService.GetMostSevereFixAsync( - document, TextSpan.FromBounds(0, 0), new DefaultCodeActionRequestPriorityProvider(), CodeActionOptions.DefaultProvider, CancellationToken.None); + document, TextSpan.FromBounds(0, 0), new DefaultCodeActionRequestPriorityProvider(), CancellationToken.None); var fixer1 = (MockFixer)fixers.Single().Value; var fixer2 = (MockFixer)reference.Fixers.Single(); @@ -83,7 +83,7 @@ public async Task TestGetFixesAsyncWithDuplicateDiagnostics() GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); // Verify that we do not crash when computing fixes. - _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); + _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); // Verify that code fix is invoked with both the diagnostics in the context, // i.e. duplicate diagnostics are not silently discarded by the CodeFixService. @@ -109,7 +109,7 @@ public async Task TestGetFixesAsyncHasNoDuplicateConfigurationActions() GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); // Verify registered configuration code actions do not have duplicates. - var fixCollections = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); + var fixCollections = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); var codeActions = fixCollections.SelectManyAsArray(c => c.Fixes.Select(f => f.Action)); Assert.Equal(7, codeActions.Length); var uniqueTitles = new HashSet(); @@ -141,14 +141,14 @@ public async Task TestGetFixesAsyncForFixableAndNonFixableAnalyzersAsync() // Verify only analyzerWithFix is executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Normal'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priorityProvider: new DefaultCodeActionRequestPriorityProvider(CodeActionRequestPriority.Default), CodeActionOptions.DefaultProvider, + priorityProvider: new DefaultCodeActionRequestPriorityProvider(CodeActionRequestPriority.Default), cancellationToken: CancellationToken.None); Assert.True(analyzerWithFix.ReceivedCallback); Assert.False(analyzerWithoutFix.ReceivedCallback); // Verify both analyzerWithFix and analyzerWithoutFix are executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Lowest'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priorityProvider: new DefaultCodeActionRequestPriorityProvider(CodeActionRequestPriority.Lowest), CodeActionOptions.DefaultProvider, + priorityProvider: new DefaultCodeActionRequestPriorityProvider(CodeActionRequestPriority.Lowest), cancellationToken: CancellationToken.None); Assert.True(analyzerWithFix.ReceivedCallback); Assert.True(analyzerWithoutFix.ReceivedCallback); @@ -177,7 +177,7 @@ public async Task TestGetFixesAsyncForDocumentDiagnosticAnalyzerAsync() // Verify both analyzers are executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Normal'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priorityProvider: new DefaultCodeActionRequestPriorityProvider(CodeActionRequestPriority.Default), CodeActionOptions.DefaultProvider, + priorityProvider: new DefaultCodeActionRequestPriorityProvider(CodeActionRequestPriority.Default), cancellationToken: CancellationToken.None); Assert.True(documentDiagnosticAnalyzer.ReceivedCallback); } @@ -207,7 +207,7 @@ public async Task TestGetFixesAsyncForGeneratorDiagnosticAsync() Assert.False(codeFix.Called); var fixCollectionSet = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priorityProvider: new DefaultCodeActionRequestPriorityProvider(CodeActionRequestPriority.Default), CodeActionOptions.DefaultProvider, + priorityProvider: new DefaultCodeActionRequestPriorityProvider(CodeActionRequestPriority.Default), cancellationToken: CancellationToken.None); Assert.True(codeFix.Called); var fixCollection = Assert.Single(fixCollectionSet); @@ -293,7 +293,7 @@ private static async Task> GetAddedFixesAsync( var reference = new MockAnalyzerReference(codefix, ImmutableArray.Create(diagnosticAnalyzer)); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); document = project.Documents.Single(); - var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); + var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); if (exception) { @@ -318,7 +318,7 @@ private static async Task GetFirstDiagnosticWithFixWithExceptionValidationAsync( GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager); var unused = await tuple.codeFixService.GetMostSevereFixAsync( - document, TextSpan.FromBounds(0, 0), new DefaultCodeActionRequestPriorityProvider(), CodeActionOptions.DefaultProvider, CancellationToken.None); + document, TextSpan.FromBounds(0, 0), new DefaultCodeActionRequestPriorityProvider(), CancellationToken.None); Assert.True(extensionManager.IsDisabled(codefix)); Assert.False(extensionManager.IsIgnored(codefix)); Assert.True(errorReported); @@ -354,7 +354,7 @@ private static (EditorTestWorkspace workspace, DiagnosticAnalyzerService analyze } var analyzerReference = new TestAnalyzerReferenceByLanguage(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap()); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var diagnosticService = Assert.IsType(workspace.GetService()); var logger = SpecializedCollections.SingletonEnumerable(new Lazy(() => new TestErrorLogger())); @@ -778,7 +778,7 @@ private static async Task> GetNuGetAndVsixCode var document = project.Documents.Single(); - return await fixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); + return await fixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); } private sealed class NuGetCodeFixProvider : AbstractNuGetOrVsixCodeFixProvider @@ -879,7 +879,7 @@ public async Task TestAdditionalDocumentCodeFixAsync() var tuple = ServiceSetup(fixers, additionalDocument: new EditorTestHostDocument("Additional Document", filePath: "test.txt")); using var workspace = tuple.workspace; GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var txtDocument, out var extensionManager, analyzerReference, documentKind: TextDocumentKind.AdditionalDocument); - var txtDocumentCodeFixes = await tuple.codeFixService.GetFixesAsync(txtDocument, TextSpan.FromBounds(0, 1), CodeActionOptions.DefaultProvider, CancellationToken.None); + var txtDocumentCodeFixes = await tuple.codeFixService.GetFixesAsync(txtDocument, TextSpan.FromBounds(0, 1), CancellationToken.None); Assert.Equal(2, txtDocumentCodeFixes.Length); var txtDocumentCodeFixTitles = txtDocumentCodeFixes.Select(s => s.Fixes.Single().Action.Title).ToImmutableArray(); Assert.Contains(fixer1.Title, txtDocumentCodeFixTitles); @@ -896,7 +896,7 @@ public async Task TestAdditionalDocumentCodeFixAsync() tuple = ServiceSetup(fixers, additionalDocument: new EditorTestHostDocument("Additional Document", filePath: "test.log")); using var workspace2 = tuple.workspace; GetDocumentAndExtensionManager(tuple.analyzerService, workspace2, out var logDocument, out extensionManager, analyzerReference, documentKind: TextDocumentKind.AdditionalDocument); - var logDocumentCodeFixes = await tuple.codeFixService.GetFixesAsync(logDocument, TextSpan.FromBounds(0, 1), CodeActionOptions.DefaultProvider, CancellationToken.None); + var logDocumentCodeFixes = await tuple.codeFixService.GetFixesAsync(logDocument, TextSpan.FromBounds(0, 1), CancellationToken.None); var logDocumentCodeFix = Assert.Single(logDocumentCodeFixes); var logDocumentCodeFixTitle = logDocumentCodeFix.Fixes.Single().Action.Title; Assert.Equal(fixer2.Title, logDocumentCodeFixTitle); @@ -1082,9 +1082,9 @@ await diagnosticIncrementalAnalyzer.GetDiagnosticsForIdsAsync( var lowPriorityAnalyzerData = new SuggestedActionPriorityProvider.LowPriorityAnalyzersAndDiagnosticIds(); var priorityProvider = new SuggestedActionPriorityProvider(CodeActionRequestPriority.Default, lowPriorityAnalyzerData); - var normalPriFixes = await tuple.codeFixService.GetFixesAsync(sourceDocument, testSpan, priorityProvider, CodeActionOptions.DefaultProvider, CancellationToken.None); + var normalPriFixes = await tuple.codeFixService.GetFixesAsync(sourceDocument, testSpan, priorityProvider, CancellationToken.None); priorityProvider = new SuggestedActionPriorityProvider(CodeActionRequestPriority.Low, lowPriorityAnalyzerData); - var lowPriFixes = await tuple.codeFixService.GetFixesAsync(sourceDocument, testSpan, priorityProvider, CodeActionOptions.DefaultProvider, CancellationToken.None); + var lowPriFixes = await tuple.codeFixService.GetFixesAsync(sourceDocument, testSpan, priorityProvider, CancellationToken.None); if (expectedNoFixes) { diff --git a/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs index 0b046927780db..f0251f40af338 100644 --- a/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs @@ -32,7 +32,7 @@ private static SyntaxNode Simplify( .AddProject(projectId, languageName, $"{languageName}.dll", languageName).GetRequiredProject(projectId); var normalizedSyntax = syntaxNode.NormalizeWhitespace().ToFullString(); - var document = project.AddMetadataReference(TestMetadata.Net451.mscorlib) + var document = project.AddMetadataReference(NetFramework.mscorlib) .AddDocument("Fake Document", SourceText.From(normalizedSyntax)); var root = document.GetRequiredSyntaxRootAsync(default).AsTask().Result; @@ -53,16 +53,16 @@ private static SyntaxNode WrapExpressionInBoilerplate(SyntaxNode expression, Syn codeDefFactory.NamespaceImportDeclaration(codeDefFactory.IdentifierName("System")), codeDefFactory.ClassDeclaration( "C", - members: new[] - { + members: + [ codeDefFactory.MethodDeclaration( "Dummy", returnType: null, - statements: new[] - { + statements: + [ codeDefFactory.LocalDeclarationStatement("test", expression) - }) - }) + ]) + ]) ); } diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs index 3a9abd1f05eec..ccfc183b2f1bc 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs @@ -538,7 +538,7 @@ internal static async Task TestAddAttributeAsync( var codeGenerator = testContext.Document.GetRequiredLanguageService(); var options = await testContext.Document.GetCodeGenerationOptionsAsync(CancellationToken.None); var info = codeGenerator.GetInfo(CodeGenerationContext.Default, options, oldNode.SyntaxTree.Options); - var newNode = codeGenerator.AddAttributes(oldNode, new[] { attr }, target, info, CancellationToken.None) + var newNode = codeGenerator.AddAttributes(oldNode, [attr], target, info, CancellationToken.None) .WithAdditionalAnnotations(Formatter.Annotation); testContext.Result = testContext.Document.WithSyntaxRoot(testContext.SemanticModel.SyntaxTree.GetRoot().ReplaceNode(oldNode, newNode)); } diff --git a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs index b350a11eb52c0..fc2789aba947c 100644 --- a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs +++ b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs @@ -47,7 +47,7 @@ public async Task TestProjectRefactoringAsync() var reference = new StubAnalyzerReference(); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); var document = project.Documents.Single(); - var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); + var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); var stubRefactoringAction = refactorings.Single(refactoring => refactoring.CodeActions.FirstOrDefault().action?.Title == nameof(StubRefactoring)); Assert.True(stubRefactoringAction is object); @@ -85,8 +85,7 @@ public async Task TestTypeScriptRefactorings() var refactoringService = workspace.GetService(); var document = workspace.CurrentSolution.Projects.Single().Documents.Single(); - var optionsProvider = workspace.GlobalOptions.GetCodeActionOptionsProvider(); - var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), optionsProvider, CancellationToken.None); + var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); Assert.Equal($"Blocking=false", refactorings.Single().CodeActions.Single().action.Title); } @@ -107,7 +106,7 @@ private static async Task VerifyRefactoringDisabledAsync() var project = workspace.CurrentSolution.Projects.Single(); var document = project.Documents.Single(); var extensionManager = (EditorLayerExtensionManager.ExtensionManager)document.Project.Solution.Services.GetRequiredService(); - var result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); + var result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); Assert.True(extensionManager.IsDisabled(codeRefactoring)); Assert.False(extensionManager.IsIgnored(codeRefactoring)); @@ -170,7 +169,7 @@ public async Task TestAdditionalDocumentRefactoringAsync() // Verify available refactorings for .txt additional document var txtAdditionalDocument = project.AdditionalDocuments.Single(t => t.Name == "test.txt"); - var txtRefactorings = await refactoringService.GetRefactoringsAsync(txtAdditionalDocument, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); + var txtRefactorings = await refactoringService.GetRefactoringsAsync(txtAdditionalDocument, TextSpan.FromBounds(0, 0), CancellationToken.None); Assert.Equal(2, txtRefactorings.Length); var txtRefactoringTitles = txtRefactorings.Select(s => s.CodeActions.Single().action.Title).ToImmutableArray(); Assert.Contains(refactoring1.Title, txtRefactoringTitles); @@ -185,7 +184,7 @@ public async Task TestAdditionalDocumentRefactoringAsync() // Verify available refactorings for .log additional document var logAdditionalDocument = project.AdditionalDocuments.Single(t => t.Name == "test.log"); - var logRefactorings = await refactoringService.GetRefactoringsAsync(logAdditionalDocument, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); + var logRefactorings = await refactoringService.GetRefactoringsAsync(logAdditionalDocument, TextSpan.FromBounds(0, 0), CancellationToken.None); var logRefactoring = Assert.Single(logRefactorings); var logRefactoringTitle = logRefactoring.CodeActions.Single().action.Title; Assert.Equal(refactoring2.Title, logRefactoringTitle); @@ -209,7 +208,7 @@ public async Task TestAnalyzerConfigDocumentRefactoringAsync() // Verify available refactorings for .editorconfig document var editorConfig = project.AnalyzerConfigDocuments.Single(t => t.Name == ".editorconfig"); - var editorConfigRefactorings = await refactoringService.GetRefactoringsAsync(editorConfig, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); + var editorConfigRefactorings = await refactoringService.GetRefactoringsAsync(editorConfig, TextSpan.FromBounds(0, 0), CancellationToken.None); Assert.Equal(2, editorConfigRefactorings.Length); var editorConfigRefactoringTitles = editorConfigRefactorings.Select(s => s.CodeActions.Single().action.Title).ToImmutableArray(); Assert.Contains(refactoring1.Title, editorConfigRefactoringTitles); @@ -224,7 +223,7 @@ public async Task TestAnalyzerConfigDocumentRefactoringAsync() // Verify available refactorings for .globalconfig document var globalConfig = project.AnalyzerConfigDocuments.Single(t => t.Name == ".globalconfig"); - var globalConfigRefactorings = await refactoringService.GetRefactoringsAsync(globalConfig, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); + var globalConfigRefactorings = await refactoringService.GetRefactoringsAsync(globalConfig, TextSpan.FromBounds(0, 0), CancellationToken.None); var globalConfigRefactoring = Assert.Single(globalConfigRefactorings); var globalConfigRefactoringTitle = globalConfigRefactoring.CodeActions.Single().action.Title; Assert.Equal(refactoring2.Title, globalConfigRefactoringTitle); @@ -257,8 +256,8 @@ public override Task ComputeRefactoringsAsync(CodeRefactoringContext context) #pragma warning disable RS0034 // Exported parts should be marked with 'ImportingConstructorAttribute' [ExportCodeRefactoringProvider( LanguageNames.CSharp, - DocumentKinds = new[] { nameof(TextDocumentKind.AdditionalDocument), nameof(TextDocumentKind.AnalyzerConfigDocument) }, - DocumentExtensions = new[] { ".txt", ".editorconfig" })] + DocumentKinds = [nameof(TextDocumentKind.AdditionalDocument), nameof(TextDocumentKind.AnalyzerConfigDocument)], + DocumentExtensions = [".txt", ".editorconfig"])] [Shared] internal sealed class NonSourceFileRefactoringWithDocumentKindsAndExtensions : AbstractNonSourceFileRefactoring { @@ -267,7 +266,7 @@ public NonSourceFileRefactoringWithDocumentKindsAndExtensions() : base(nameof(No [ExportCodeRefactoringProvider( LanguageNames.CSharp, - DocumentKinds = new[] { nameof(TextDocumentKind.AdditionalDocument), nameof(TextDocumentKind.AnalyzerConfigDocument) })] + DocumentKinds = [nameof(TextDocumentKind.AdditionalDocument), nameof(TextDocumentKind.AnalyzerConfigDocument)])] [Shared] internal sealed class NonSourceFileRefactoringWithDocumentKinds : AbstractNonSourceFileRefactoring { @@ -276,7 +275,7 @@ public NonSourceFileRefactoringWithDocumentKinds() : base(nameof(NonSourceFileRe [ExportCodeRefactoringProvider( LanguageNames.CSharp, - DocumentExtensions = new[] { ".txt", ".editorconfig" })] + DocumentExtensions = [".txt", ".editorconfig"])] [Shared] internal sealed class NonSourceFileRefactoringWithDocumentExtensions : AbstractNonSourceFileRefactoring { diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index 578235422e5f1..2d960247d8df2 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs @@ -58,7 +58,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalse() using var workspace = CreateWorkspace(); var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new Analyzer())); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var document = GetDocumentFromIncompleteProject(workspace); @@ -83,7 +83,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseFSAOn() var globalOptions = GetGlobalOptions(workspace); globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var document = GetDocumentFromIncompleteProject(workspace); OpenDocumentAndMakeActive(document, workspace); @@ -97,7 +97,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseWhenFileOpened() using var workspace = CreateWorkspace(); var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new Analyzer())); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var document = GetDocumentFromIncompleteProject(workspace); @@ -112,7 +112,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseWhenFileOpenedWithCompilerA using var workspace = CreateWorkspace(); var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(new CSharpCompilerDiagnosticAnalyzer())); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var document = GetDocumentFromIncompleteProject(workspace); @@ -132,7 +132,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalseWithCompilerAnalyzerFSAOn() var globalOptions = GetGlobalOptions(workspace); globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var document = GetDocumentFromIncompleteProject(workspace); @@ -151,7 +151,7 @@ public async Task TestDisabledByDefaultAnalyzerEnabledWithEditorConfig(bool enab var globalOptions = GetGlobalOptions(workspace); globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var project = workspace.AddProject( ProjectInfo.Create( @@ -252,7 +252,7 @@ public async Task TestHostAnalyzerOrderingAsync() new Analyzer() )); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var project = workspace.AddProject( ProjectInfo.Create( @@ -268,8 +268,8 @@ public async Task TestHostAnalyzerOrderingAsync() var analyzers = await incrementalAnalyzer.GetAnalyzersTestOnlyAsync(project, CancellationToken.None).ConfigureAwait(false); var analyzersArray = analyzers.ToArray(); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ typeof(FileContentLoadAnalyzer), typeof(GeneratorDiagnosticsPlaceholderAnalyzer), typeof(CSharpCompilerDiagnosticAnalyzer), @@ -279,7 +279,7 @@ public async Task TestHostAnalyzerOrderingAsync() typeof(Priority10Analyzer), typeof(Priority15Analyzer), typeof(Priority20Analyzer) - }, analyzersArray.Select(a => a.GetType())); + ], analyzersArray.Select(a => a.GetType())); } [Fact] @@ -295,7 +295,7 @@ public async Task TestHostAnalyzerErrorNotLeaking() var globalOptions = GetGlobalOptions(workspace); globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution); - workspace.TryApplyChanges(solution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(solution.WithAnalyzerReferences([analyzerReference])); var projectId = ProjectId.CreateNewId(); var project = workspace.AddProject( @@ -305,12 +305,12 @@ public async Task TestHostAnalyzerErrorNotLeaking() "Dummy", "Dummy", LanguageNames.CSharp, - documents: new[] { + documents: [ DocumentInfo.Create( DocumentId.CreateNewId(projectId), "test.cs", loader: TextLoader.From(TextAndVersion.Create(SourceText.From("class A {}"), VersionStamp.Create(), filePath: "test.cs")), - filePath: "test.cs")})); + filePath: "test.cs")])); var exportProvider = workspace.Services.SolutionServices.ExportProvider; var service = Assert.IsType(exportProvider.GetExportedValue()); @@ -384,12 +384,12 @@ private static AdhocWorkspace CreateWorkspaceWithProjectAndAnalyzer(DiagnosticAn "Dummy", LanguageNames.CSharp, filePath: "z:\\Dummy.csproj", - documents: new[] { + documents: [ DocumentInfo.Create( DocumentId.CreateNewId(projectId), "test.cs", loader: TextLoader.From(TextAndVersion.Create(SourceText.From("class A {}"), VersionStamp.Create(), filePath: "test.cs")), - filePath: "z:\\test.cs")})); + filePath: "z:\\test.cs")])); Assert.True(workspace.TryApplyChanges(solution)); @@ -434,7 +434,7 @@ internal async Task TestAdditionalFileAnalyzer(bool registerFromInitialize, bool } var analyzerReference = new AnalyzerImageReference(analyzers); - project = project.WithAnalyzerReferences(new[] { analyzerReference }) + project = project.WithAnalyzerReferences([analyzerReference]) .AddAdditionalDocument(name: "dummy.txt", text: "Additional File Text", filePath: "dummy.txt").Project; if (testMultiple) { @@ -505,7 +505,7 @@ internal async Task TestDiagnosticSuppressor(bool includeAnalyzer, bool includeS workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, analysisScope); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var project = workspace.CurrentSolution.Projects.Single(); var document = project.Documents.Single(); @@ -620,7 +620,7 @@ void M() workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, LanguageNames.CSharp, compilerDiagnosticsScope); workspace.InitializeDocuments(TestWorkspace.CreateWorkspaceElement(LanguageNames.CSharp, files: files, sourceGeneratedFiles: sourceGeneratedFiles), openDocuments: false); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var project = workspace.CurrentSolution.Projects.Single(); var document = isSourceGenerated ? (await project.GetSourceGeneratedDocumentsAsync(CancellationToken.None)).Single() : project.Documents.Single(); @@ -699,7 +699,7 @@ internal async Task TestOnlyRequiredAnalyzerExecutedDuringDiagnosticComputation( var analyzer2 = new NamedTypeAnalyzer(); var analyzerIdsToRequestDiagnostics = new[] { analyzer1Id }; var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer1, analyzer2)); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var project = workspace.CurrentSolution.Projects.Single(); var document = documentAnalysis ? project.Documents.Single() : null; var diagnosticsMapResults = await DiagnosticComputer.GetDiagnosticsAsync( @@ -813,7 +813,7 @@ void M() var analyzer = new CancellationTestAnalyzer(actionKind); var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var project = workspace.CurrentSolution.Projects.Single(); var document = project.Documents.Single(); diff --git a/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs b/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs index 08870116cfe9e..bab2a0ad00529 100644 --- a/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/SuppressMessageAttributeWorkspaceTests.cs @@ -47,18 +47,18 @@ public UnconditionalSuppressMessageAttribute(string category, string checkId) }"; return CSharpCompilation.Create("unconditionalsuppress", options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary), - syntaxTrees: new[] { CSharpSyntaxTree.ParseText(unconditionalSuppressMessageDef) }, - references: new[] { TestBase.MscorlibRef }).EmitToImageReference(); + syntaxTrees: [CSharpSyntaxTree.ParseText(unconditionalSuppressMessageDef)], + references: [TestBase.MscorlibRef]).EmitToImageReference(); }, LazyThreadSafetyMode.PublicationOnly); protected override async Task VerifyAsync(string source, string language, DiagnosticAnalyzer[] analyzers, DiagnosticDescription[] expectedDiagnostics, string rootNamespace = null) { using var workspace = CreateWorkspaceFromFile(source, language, rootNamespace); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] - { + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences( + [ new AnalyzerImageReference(analyzers.ToImmutableArray()) - }).WithProjectMetadataReferences( + ]).WithProjectMetadataReferences( workspace.Projects.Single().Id, workspace.Projects.Single().MetadataReferences.Append(_unconditionalSuppressMessageRef.Value))); @@ -113,7 +113,7 @@ public class C2 { } ", - new[] { new ThrowExceptionForEachNamedTypeAnalyzer(ExceptionDispatchInfo.Capture(new Exception())) }, + [new ThrowExceptionForEachNamedTypeAnalyzer(ExceptionDispatchInfo.Capture(new Exception()))], diagnostics: [diagnostic, diagnostic, diagnostic]); } @@ -123,7 +123,7 @@ public async Task AnalyzerExceptionFromSupportedDiagnosticsCall() var diagnostic = Diagnostic("AD0001", null); await VerifyCSharpAsync("public class C { }", - new[] { new ThrowExceptionFromSupportedDiagnostics(new Exception()) }, + [new ThrowExceptionFromSupportedDiagnostics(new Exception())], diagnostics: [diagnostic]); } } diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueLanguageServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueLanguageServiceTests.cs index 677ed7aa9793b..5d24bdf93285a 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueLanguageServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueLanguageServiceTests.cs @@ -163,12 +163,14 @@ await localWorkspace.ChangeSolutionAsync(localWorkspace.CurrentSolution var documentDiagnostic = CodeAnalysis.Diagnostic.Create(diagnosticDescriptor1, Location.Create(syntaxTree, TextSpan.FromBounds(1, 2)), ["doc", "error 1"]); var projectDiagnostic = CodeAnalysis.Diagnostic.Create(diagnosticDescriptor1, Location.None, ["proj", "error 2"]); var syntaxError = CodeAnalysis.Diagnostic.Create(diagnosticDescriptor1, Location.Create(syntaxTree, TextSpan.FromBounds(1, 2)), ["doc", "syntax error 3"]); + var rudeEditDiagnostic = new RudeEditDiagnostic(RudeEditKind.Delete, TextSpan.FromBounds(2, 3), arguments: ["x"]).ToDiagnostic(syntaxTree); return new() { + Solution = solution, ModuleUpdates = new ModuleUpdates(ModuleUpdateStatus.Ready, []), Diagnostics = [new ProjectDiagnostics(project.Id, [documentDiagnostic, projectDiagnostic])], - RudeEdits = [(documentId, [new RudeEditDiagnostic(RudeEditKind.Delete, TextSpan.FromBounds(2, 3), arguments: ["x"])])], + RudeEdits = [new ProjectDiagnostics(project.Id, [rudeEditDiagnostic])], SyntaxError = syntaxError }; }; diff --git a/src/EditorFeatures/Test/Extensions/CollectionExtensionsTest.cs b/src/EditorFeatures/Test/Extensions/CollectionExtensionsTest.cs index 5efac1fe346d4..cc184d27aaac6 100644 --- a/src/EditorFeatures/Test/Extensions/CollectionExtensionsTest.cs +++ b/src/EditorFeatures/Test/Extensions/CollectionExtensionsTest.cs @@ -17,7 +17,7 @@ public class CollectionExtensionsTest public void PushReverse1() { var stack = new Stack(); - stack.PushReverse(new int[] { 1, 2, 3 }); + stack.PushReverse([1, 2, 3]); Assert.Equal(1, stack.Pop()); Assert.Equal(2, stack.Pop()); Assert.Equal(3, stack.Pop()); @@ -37,7 +37,7 @@ public void PushReverse3() { var stack = new Stack(); stack.Push(3); - stack.PushReverse(new int[] { 1, 2 }); + stack.PushReverse([1, 2]); Assert.Equal(1, stack.Pop()); Assert.Equal(2, stack.Pop()); Assert.Equal(3, stack.Pop()); diff --git a/src/EditorFeatures/Test/Extensions/SetExtensionTests.cs b/src/EditorFeatures/Test/Extensions/SetExtensionTests.cs index d68bac12d1858..e330e4406ec1b 100644 --- a/src/EditorFeatures/Test/Extensions/SetExtensionTests.cs +++ b/src/EditorFeatures/Test/Extensions/SetExtensionTests.cs @@ -16,8 +16,8 @@ public class SetExtensionTests public void TestAddAll() { var set = new HashSet() { "a", "b", "c" }; - Assert.False(set.AddAll(new[] { "b", "c" })); - Assert.True(set.AddAll(new[] { "c", "d" })); - Assert.True(set.AddAll(new[] { "e", "f" })); + Assert.False(set.AddAll(["b", "c"])); + Assert.True(set.AddAll(["c", "d"])); + Assert.True(set.AddAll(["e", "f"])); } } diff --git a/src/EditorFeatures/Test/FindSymbols/SymbolTreeInfoTests.cs b/src/EditorFeatures/Test/FindSymbols/SymbolTreeInfoTests.cs index 85fddedcdbc79..549b891f73c17 100644 --- a/src/EditorFeatures/Test/FindSymbols/SymbolTreeInfoTests.cs +++ b/src/EditorFeatures/Test/FindSymbols/SymbolTreeInfoTests.cs @@ -22,7 +22,7 @@ public async Task TestSymbolTreeInfoForMetadataWithDifferentProperties1() var project = solution.Projects.Single(); var reference1 = (PortableExecutableReference)project.MetadataReferences.First(); - var reference2 = reference1.WithAliases(new[] { "Alias" }); + var reference2 = reference1.WithAliases(["Alias"]); var info1 = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( solution, reference1, checksum: null, CancellationToken.None); @@ -43,7 +43,7 @@ public async Task TestSymbolTreeInfoForMetadataWithDifferentProperties2() var project = solution.Projects.Single(); var reference1 = (PortableExecutableReference)project.MetadataReferences.First(); - var reference2 = reference1.WithAliases(new[] { "Alias" }); + var reference2 = reference1.WithAliases(["Alias"]); var checksum1 = SymbolTreeInfo.GetMetadataChecksum(solution.Services, reference1, CancellationToken.None); var info1 = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( @@ -66,7 +66,7 @@ public async Task TestSymbolTreeInfoForMetadataWithDifferentProperties3() var project = solution.Projects.Single(); var reference1 = (PortableExecutableReference)project.MetadataReferences.First(); - var reference2 = reference1.WithAliases(new[] { "Alias" }); + var reference2 = reference1.WithAliases(["Alias"]); var checksum1 = SymbolTreeInfo.GetMetadataChecksum(solution.Services, reference1, CancellationToken.None); var info1 = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( @@ -88,7 +88,7 @@ public async Task TestSymbolTreeInfoForMetadataWithDifferentProperties4() var project = solution.Projects.Single(); var reference1 = (PortableExecutableReference)project.MetadataReferences.First(); - var reference2 = reference1.WithAliases(new[] { "Alias" }); + var reference2 = reference1.WithAliases(["Alias"]); var info1 = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( solution, reference1, checksum: null, CancellationToken.None); diff --git a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs index a1689f906e834..e462801ef3299 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.TestContext.cs @@ -300,7 +300,7 @@ internal Document GetDocument(MetadataAsSourceFile file) using var reader = File.OpenRead(file.FilePath); var stringText = EncodedStringText.Create(reader); - Assert.True(_metadataAsSourceService.TryAddDocumentToWorkspace(file.FilePath, stringText.Container)); + Assert.True(_metadataAsSourceService.TryAddDocumentToWorkspace(file.FilePath, stringText.Container, out var _)); return stringText.Container.GetRelatedDocuments().Single(); } diff --git a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs index 849beda1c7801..8b641988f588b 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/AbstractMetadataAsSourceTests.cs @@ -28,11 +28,11 @@ public virtual Task InitializeAsync() AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.MscorlibRef_v46, "mscorlib.v4_6_1038_0.dll", ImmutableArray.Create(Net461.ReferenceInfos.mscorlib.ImageBytes)); AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.SystemRef_v46, "System.v4_6_1038_0.dll", ImmutableArray.Create(Net461.ReferenceInfos.System.ImageBytes)); AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.SystemCoreRef_v46, "System.Core.v4_6_1038_0.dll", ImmutableArray.Create(Net461.ReferenceInfos.SystemCore.ImageBytes)); - AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.ValueTupleRef, "System.ValueTuple.dll", ImmutableArray.Create(TestResources.NetFX.ValueTuple.tuplelib)); - AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.SystemRuntimeFacadeRef, "System.Runtime.dll", ImmutableArray.Create(TestMetadata.ResourcesNet451.SystemRuntime)); - AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.MsvbRef, "Microsoft.VisualBasic.dll", ImmutableArray.Create(TestMetadata.ResourcesNet451.MicrosoftVisualBasic)); - AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.SystemXmlRef, "System.Xml.v4_0_30319.dll", ImmutableArray.Create(TestMetadata.ResourcesNet451.SystemXml)); - AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.SystemXmlLinqRef, "System.Xml.Linq.v4_0_30319.dll", ImmutableArray.Create(TestMetadata.ResourcesNet451.SystemXmlLinq)); + AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.ValueTupleRef, "System.ValueTuple.dll", ImmutableArray.Create(Net461.ExtraReferenceInfos.SystemValueTuple.ImageBytes)); + AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.SystemRuntimeFacadeRef, "System.Runtime.dll", ImmutableArray.Create(Net461.Resources.SystemRuntime)); + AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.MsvbRef, "Microsoft.VisualBasic.dll", ImmutableArray.Create(Net461.Resources.MicrosoftVisualBasic)); + AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.SystemXmlRef, "System.Xml.v4_0_30319.dll", ImmutableArray.Create(Net461.Resources.SystemXml)); + AssemblyResolver.TestAccessor.AddInMemoryImage(TestBase.SystemXmlLinqRef, "System.Xml.Linq.v4_0_30319.dll", ImmutableArray.Create(Net461.Resources.SystemXmlLinq)); return Task.CompletedTask; } @@ -76,7 +76,7 @@ internal static async Task TestNotReusedOnAssemblyDiffersAsync(string projectLan var projectId = ProjectId.CreateNewId(); var metadataProject = context.CurrentSolution .AddProject(projectId, "Metadata", "Metadata", LanguageNames.CSharp).GetProject(projectId) - .AddMetadataReference(TestMetadata.Net451.mscorlib) + .AddMetadataReference(NetFramework.mscorlib) .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release)); var references = new List(); diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs index e520df54d4ca1..29e81ac37afbf 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs @@ -157,9 +157,9 @@ public class [|C|] {string.Format(FeaturesResources.Found_single_assembly_0, "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")} {string.Format(FeaturesResources.Load_from_0, "mscorlib.v4_6_1038_0.dll")} ------------------ -{string.Format(FeaturesResources.Resolve_0, "System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51")} -{string.Format(FeaturesResources.Found_single_assembly_0, "System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51")} -{string.Format(FeaturesResources.Load_from_0, "System.ValueTuple.dll")} +{string.Format(FeaturesResources.Resolve_0, "System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51")} +{string.Format(FeaturesResources.Found_single_assembly_0, "System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51")} +{string.Format(FeaturesResources.Load_from_0, "System.ValueTuple (net461)")} #endif", }; @@ -173,8 +173,8 @@ public async Task TestValueTuple(bool signaturesOnly) var expected = signaturesOnly switch { - true => $@"#region {FeaturesResources.Assembly} System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 -// System.ValueTuple.dll + true => $@"#region {FeaturesResources.Assembly} System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 +// System.ValueTuple (net461) #endregion using System.Collections; @@ -199,12 +199,13 @@ public struct [|ValueTuple|] : IEquatable, IStructuralEquatable, ISt public override string ToString(); }} }}", - false => $@"#region {FeaturesResources.Assembly} System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 -// System.ValueTuple.dll + false => $@"#region {FeaturesResources.Assembly} System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 +// System.ValueTuple (net461) // Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Collections; +using System.Numerics.Hashing; using System.Runtime.InteropServices; namespace System; @@ -336,67 +337,49 @@ public static (T1, T2, T3, T4, T5, T6, T7, T8) Create $@"#Region ""{FeaturesResources.Assembly} System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"" -' System.ValueTuple.dll + true => $@"#Region ""{FeaturesResources.Assembly} System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"" +' System.ValueTuple (net461) #End Region Imports System.Collections @@ -226,12 +226,13 @@ Public Overrides Function GetHashCode() As Integer Public Overrides Function ToString() As String End Structure End Namespace", - false => $@"#region {FeaturesResources.Assembly} System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 + false => $@"#region {FeaturesResources.Assembly} System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 // {FeaturesResources.location_unknown} // Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} #endregion using System.Collections; +using System.Numerics.Hashing; using System.Runtime.InteropServices; namespace System; @@ -363,67 +364,49 @@ public static (T1, T2, T3, T4, T5, T6, T7, T8) Create().GetEditorOperations(_view); + HostDocument = Workspace.Documents.First(); + _view = HostDocument.GetTextView(); + _view.Caret.MoveTo(new SnapshotPoint(_view.TextSnapshot, HostDocument.CursorPosition.Value)); + EditorOperations = Workspace.GetService().GetEditorOperations(_view); _historyRegistry = Workspace.ExportProvider.GetExport().Value; - _mockRefactorNotifyService = new MockRefactorNotifyService + RefactorNotifyService = new MockRefactorNotifyService { OnBeforeSymbolRenamedReturnValue = onBeforeGlobalSymbolRenamedReturnValue, OnAfterSymbolRenamedReturnValue = onAfterGlobalSymbolRenamedReturnValue @@ -105,14 +102,14 @@ public RenameTrackingTestState( Workspace.GetService(), Workspace.GetService()); - _tagger = tracker.CreateTagger(_hostDocument.GetTextBuffer()); + _tagger = tracker.CreateTagger(HostDocument.GetTextBuffer()); if (languageName is LanguageNames.CSharp or LanguageNames.VisualBasic) { _codeRefactoringProvider = new RenameTrackingCodeRefactoringProvider( _historyRegistry, - [_mockRefactorNotifyService]); + [RefactorNotifyService]); } else { @@ -170,7 +167,7 @@ public async Task TryGetCodeActionAsync(TextSpan? textSpan = null) { var span = textSpan ?? new TextSpan(_view.Caret.Position.BufferPosition, 0); - var document = this.Workspace.CurrentSolution.GetDocument(_hostDocument.Id); + var document = this.Workspace.CurrentSolution.GetDocument(HostDocument.Id); var actions = new List(); var context = new CodeRefactoringContext( diff --git a/src/EditorFeatures/Test/Snippets/RoslynLSPSnippetConvertTests.cs b/src/EditorFeatures/Test/Snippets/RoslynLSPSnippetConvertTests.cs index 5d91ebb1357f7..cf998b5eae274 100644 --- a/src/EditorFeatures/Test/Snippets/RoslynLSPSnippetConvertTests.cs +++ b/src/EditorFeatures/Test/Snippets/RoslynLSPSnippetConvertTests.cs @@ -506,9 +506,9 @@ private static ImmutableArray GetSnippetPlaceholders(string if (kvp.Key.Length > 0) { var spans = kvp.Value; - var identifier = text.Substring(spans[0].Start, spans[0].Length); + var placeholderText = text.Substring(spans[0].Start, spans[0].Length); var placeholders = spans.Select(span => span.Start).ToImmutableArray(); - arrayBuilder.Add(new SnippetPlaceholder(identifier, placeholders)); + arrayBuilder.Add(new SnippetPlaceholder(placeholderText, placeholders)); } } diff --git a/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs b/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs index e1c87e5416fe2..a51b69ef6891b 100644 --- a/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs +++ b/src/EditorFeatures/Test/Structure/StructureTaggerTests.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Implementation.Structure; +using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tagging; using Microsoft.CodeAnalysis.Structure; @@ -325,6 +326,39 @@ End Sub hints.Do(v => v.TextView_TestOnly.Close()); } + [WpfFact] + [WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2094051")] + public async Task IfShouldBeCollapsed() + { + var code = @" +Module Program + Sub Main(args As String()) + Dim str = """" + If str.Contains(""foo"") Then + + End If + End Sub +End Module"; + + using var workspace = EditorTestWorkspace.CreateVisualBasic(code, composition: EditorTestCompositions.EditorFeaturesWpf); + var tags = await GetTagsFromWorkspaceAsync(workspace); + Assert.Collection(tags, programTag => + { + Assert.Equal("Module Program", GetHeaderText(programTag)); + Assert.Equal(8, GetCollapsedHintLineCount(programTag)); + }, + mainTag => + { + Assert.Equal("Sub Main(args As String())", GetHeaderText(mainTag)); + Assert.Equal(6, GetCollapsedHintLineCount(mainTag)); + }, + IfTag => + { + Assert.Equal("If str.Contains(\"foo\") Then", GetHeaderText(IfTag)); + Assert.Equal(3, GetCollapsedHintLineCount(IfTag)); + }); + } + #pragma warning disable CS0618 // Type or member is obsolete private static async Task> GetTagsFromWorkspaceAsync(EditorTestWorkspace workspace) { diff --git a/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs b/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs index adaa718789885..5b768839c6340 100644 --- a/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs +++ b/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Remote.Testing; @@ -34,7 +35,7 @@ private static Solution AddProjectWithMetadataReferences(Solution solution, stri projectName, projectName, languageName, - metadataReferences: new[] { metadataReference }, + metadataReferences: [metadataReference], projectReferences: projectReferences.Select(p => new ProjectReference(p))); return solution.AddProject(pi).AddDocument(did, $"{projectName}.{suffix}", SourceText.From(code)); } @@ -57,7 +58,7 @@ namespace N { public abstract class BaseClass { } } -", MscorlibRefPortable); +", Net40.References.mscorlib); var portableProject = GetPortableProject(solution); @@ -68,7 +69,7 @@ namespace M { public class DerivedClass : BaseClass { } } -", MscorlibRef, portableProject.Id); +", Net461.References.mscorlib, portableProject.Id); // get symbols for types var portableCompilation = await GetPortableProject(solution).GetCompilationAsync(); @@ -98,7 +99,7 @@ namespace N { public interface BaseInterface { } } -", MscorlibRefPortable); +", Net40.References.mscorlib); var portableProject = GetPortableProject(solution); @@ -109,7 +110,7 @@ namespace M { public interface DerivedInterface : BaseInterface { } } -", MscorlibRef, portableProject.Id); +", Net461.References.mscorlib, portableProject.Id); // get symbols for types var portableCompilation = await GetPortableProject(solution).GetCompilationAsync(); @@ -145,7 +146,7 @@ namespace N { public abstract class BaseClass { } } -", MscorlibRefPortable); +", Net40.References.mscorlib); var portableProject = GetPortableProject(solution); @@ -160,7 +161,7 @@ namespace M public class DerivedClass : Alias2 { } } -", MscorlibRef, portableProject.Id); +", Net461.References.mscorlib, portableProject.Id); // get symbols for types var portableCompilation = await GetPortableProject(solution).GetCompilationAsync(); @@ -190,7 +191,7 @@ namespace N { public abstract class BaseClass { } } -", MscorlibRefPortable); +", Net40.References.mscorlib); var portableProject = GetPortableProject(solution); @@ -231,7 +232,7 @@ Namespace N Public MustInherit Class BaseClass End Class End Namespace -", MscorlibRefPortable); +", Net40.References.mscorlib); var portableProject = GetPortableProject(solution); @@ -243,7 +244,7 @@ Public Class DerivedClass Inherits BaseClass End Class End Namespace -", MscorlibRef, portableProject.Id); +", Net461.References.mscorlib, portableProject.Id); // get symbols for types var portableCompilation = await GetPortableProject(solution).GetCompilationAsync(); @@ -273,7 +274,7 @@ namespace N { public abstract class BaseClass { } } -", MscorlibRefPortable); +", Net40.References.mscorlib); var portableProject = GetPortableProject(solution); @@ -285,7 +286,7 @@ Public Class DerivedClass Inherits BaseClass End Class End Namespace -", MscorlibRef, portableProject.Id); +", Net40.References.mscorlib, portableProject.Id); // get symbols for types var portableCompilation = await GetPortableProject(solution).GetCompilationAsync(); @@ -315,7 +316,7 @@ namespace N { public interface IBaseInterface { } } -", MscorlibRefPortable); +", Net40.References.mscorlib); var portableProject = GetPortableProject(solution); @@ -326,7 +327,7 @@ namespace M { public class ImplementingClass : IBaseInterface { } } -", MscorlibRef, portableProject.Id); +", Net461.References.mscorlib, portableProject.Id); // get symbols for types var portableCompilation = await GetPortableProject(solution).GetCompilationAsync(); @@ -355,7 +356,7 @@ Namespace N Public Interface IBaseInterface End Interface End Namespace -", MscorlibRefPortable); +", Net40.References.mscorlib); var portableProject = GetPortableProject(solution); @@ -367,7 +368,7 @@ Public Class ImplementingClass Implements IBaseInterface End Class End Namespace -", MscorlibRef, portableProject.Id); +", Net461.References.mscorlib, portableProject.Id); // get symbols for types var portableCompilation = await GetPortableProject(solution).GetCompilationAsync(); @@ -396,7 +397,7 @@ Namespace N Public Interface IBaseInterface End Interface End Namespace -", MscorlibRefPortable); +", Net40.References.mscorlib); var portableProject = GetPortableProject(solution); @@ -407,7 +408,7 @@ namespace M { public class ImplementingClass : IBaseInterface { } } -", MscorlibRef, portableProject.Id); +", Net40.References.mscorlib, portableProject.Id); // get symbols for types var portableCompilation = await GetPortableProject(solution).GetCompilationAsync(); @@ -431,7 +432,7 @@ public async Task DerivedMetadataClasses(TestHost host) var solution = workspace.CurrentSolution; // create a normal assembly with a type derived from the portable abstract base - solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.CSharp, @"", MscorlibRef); + solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.CSharp, @"", Net40.References.mscorlib); // get symbols for types var compilation = await GetNormalProject(solution).GetCompilationAsync(); @@ -476,7 +477,7 @@ interface IC3 : IB3 { } interface ID1 : IC1 { } interface IOther { } -", MscorlibRef); +", Net40.References.mscorlib); // get symbols for types var compilation = await GetNormalProject(solution).GetCompilationAsync(); @@ -528,7 +529,7 @@ class D1 : C1 { } class OtherClass { } struct OtherStruct { } -", MscorlibRef); +", Net40.References.mscorlib); // get symbols for types var compilation = await GetNormalProject(solution).GetCompilationAsync(); @@ -565,7 +566,7 @@ public async Task ImplementingTypesDoesProduceDelegates(TestHost host) // create a normal assembly with a type derived from the portable abstract base solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.CSharp, @" delegate void D(); -", MscorlibRef); +", Net40.References.mscorlib); // get symbols for types var compilation = await GetNormalProject(solution).GetCompilationAsync(); @@ -595,7 +596,7 @@ enum E { A, B, C, } -", MscorlibRef); +", Net40.References.mscorlib); // get symbols for types var compilation = await GetNormalProject(solution).GetCompilationAsync(); @@ -679,7 +680,7 @@ public abstract class T_BaseProject_DerivedClass2 : T_BaseProject_DerivedClass1 { } } -", MscorlibRef); +", Net40.References.mscorlib); var normalProject1 = solution.Projects.Single(); @@ -691,7 +692,7 @@ public class T_DependProject_Class : T_BaseProject_DerivedClass2 { } } -", MscorlibRef, normalProject1.Id); +", Net40.References.mscorlib, normalProject1.Id); normalProject1 = solution.GetProject(normalProject1.Id); var normalProject2 = solution.Projects.Single(p => p != normalProject1); @@ -734,7 +735,7 @@ public interface I void M(); } } -", MscorlibRefPortable); +", Net40.References.mscorlib); var portableProject1 = solution.Projects.Single(p => p.Name == "PortableProject1"); @@ -747,7 +748,7 @@ public class C : I public void M() { } } } -", MscorlibRefPortable, portableProject1.Id); +", Net40.References.mscorlib, portableProject1.Id); // get symbols for types var compilation1 = await solution.Projects.Single(p => p.Name == "PortableProject1").GetCompilationAsync(); @@ -778,7 +779,7 @@ public interface I void M(); } } -", MscorlibRefPortable); +", Net40.References.mscorlib); var portableProject1 = GetPortableProject(solution); diff --git a/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs b/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs index 04dd83e2af5f5..b647de72cd74b 100644 --- a/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs +++ b/src/EditorFeatures/Test/Utilities/SymbolEquivalenceComparerTests.cs @@ -1115,8 +1115,8 @@ void M(ref int i) { } var method_v1 = type1_v1.GetMembers("M").Single(); var method_v2 = type1_v2.GetMembers("M").Single(); - var trueComp = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true); - var falseComp = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true); + var trueComp = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); + var falseComp = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); Assert.False(trueComp.Equals(method_v1, method_v2)); Assert.False(trueComp.Equals(method_v2, method_v1)); @@ -1355,8 +1355,8 @@ class T Assert.Equal(NullableAnnotation.Annotated, a1.NullableAnnotation); Assert.Equal(NullableAnnotation.NotAnnotated, a2.NullableAnnotation); - var ignoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true); - var notIgnoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true); + var ignoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); + var notIgnoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); Assert.True(ignoreComparer.Equals(a1, a2)); Assert.True(ignoreComparer.Equals(b1, b2)); @@ -1419,8 +1419,8 @@ class T Assert.Equal(NullableAnnotation.None, a1.NullableAnnotation); Assert.Equal(NullableAnnotation.NotAnnotated, a2.NullableAnnotation); - var ignoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true); - var notIgnoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true); + var ignoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); + var notIgnoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); Assert.True(ignoreComparer.Equals(a1, a2)); Assert.True(ignoreComparer.Equals(b1, b2)); @@ -1482,8 +1482,8 @@ class T Assert.Equal(NullableAnnotation.None, a1.NullableAnnotation); Assert.Equal(NullableAnnotation.Annotated, a2.NullableAnnotation); - var ignoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true); - var notIgnoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true); + var ignoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); + var notIgnoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); Assert.True(ignoreComparer.Equals(a1, a2)); Assert.True(ignoreComparer.Equals(b1, b2)); @@ -1545,8 +1545,8 @@ class T Assert.Equal(NullableAnnotation.None, a1.NullableAnnotation); Assert.Equal(NullableAnnotation.Annotated, a2.NullableAnnotation); - var ignoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true); - var notIgnoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true); + var ignoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); + var notIgnoreComparer = new SymbolEquivalenceComparer(assemblyComparer: null, distinguishRefFromOut: true, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); Assert.True(ignoreComparer.Equals(a1, a2)); Assert.True(ignoreComparer.Equals(b1, b2)); @@ -1730,18 +1730,18 @@ namespace M [Fact] public void AssemblyComparer1() { - var references = new[] { TestMetadata.Net451.mscorlib }; + var references = new[] { NetFramework.mscorlib }; var source = "public class T {}"; var sourceV1 = "[assembly: System.Reflection.AssemblyVersion(\"1.0.0.0\")] public class T {}"; var sourceV2 = "[assembly: System.Reflection.AssemblyVersion(\"2.0.0.0\")] public class T {}"; - var a1 = (Compilation)CS.CSharpCompilation.Create("a", new[] { CS.SyntaxFactory.ParseSyntaxTree(source) }, references, CSharpDllOptions); - var a2 = (Compilation)CS.CSharpCompilation.Create("a", new[] { CS.SyntaxFactory.ParseSyntaxTree(source) }, references, CSharpDllOptions); + var a1 = (Compilation)CS.CSharpCompilation.Create("a", [CS.SyntaxFactory.ParseSyntaxTree(source)], references, CSharpDllOptions); + var a2 = (Compilation)CS.CSharpCompilation.Create("a", [CS.SyntaxFactory.ParseSyntaxTree(source)], references, CSharpDllOptions); - var b1 = (Compilation)CS.CSharpCompilation.Create("b", new[] { CS.SyntaxFactory.ParseSyntaxTree(sourceV1) }, references, CSharpSignedDllOptions); - var b2 = (Compilation)CS.CSharpCompilation.Create("b", new[] { CS.SyntaxFactory.ParseSyntaxTree(sourceV2) }, references, CSharpSignedDllOptions); - var b3 = (Compilation)CS.CSharpCompilation.Create("b", new[] { CS.SyntaxFactory.ParseSyntaxTree(sourceV2) }, references, CSharpSignedDllOptions); + var b1 = (Compilation)CS.CSharpCompilation.Create("b", [CS.SyntaxFactory.ParseSyntaxTree(sourceV1)], references, CSharpSignedDllOptions); + var b2 = (Compilation)CS.CSharpCompilation.Create("b", [CS.SyntaxFactory.ParseSyntaxTree(sourceV2)], references, CSharpSignedDllOptions); + var b3 = (Compilation)CS.CSharpCompilation.Create("b", [CS.SyntaxFactory.ParseSyntaxTree(sourceV2)], references, CSharpSignedDllOptions); var ta1 = (ITypeSymbol)a1.GlobalNamespace.GetMembers("T").Single(); var ta2 = (ITypeSymbol)a2.GlobalNamespace.GetMembers("T").Single(); @@ -1749,7 +1749,7 @@ public void AssemblyComparer1() var tb2 = (ITypeSymbol)b2.GlobalNamespace.GetMembers("T").Single(); var tb3 = (ITypeSymbol)b3.GlobalNamespace.GetMembers("T").Single(); - var identityComparer = new SymbolEquivalenceComparer(AssemblySymbolIdentityComparer.Instance, distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true); + var identityComparer = new SymbolEquivalenceComparer(AssemblySymbolIdentityComparer.Instance, distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); // same name: Assert.True(SymbolEquivalenceComparer.IgnoreAssembliesInstance.Equals(ta1, ta2)); @@ -1830,12 +1830,12 @@ .method public instance int32[] F( // 3 r2 = MetadataReference.CreateFromImage(bytes); } - var c1 = (Compilation)CS.CSharpCompilation.Create("comp1", Array.Empty(), new[] { TestMetadata.Net451.mscorlib, r1 }); - var c2 = (Compilation)CS.CSharpCompilation.Create("comp2", Array.Empty(), new[] { TestMetadata.Net451.mscorlib, r2 }); + var c1 = (Compilation)CS.CSharpCompilation.Create("comp1", Array.Empty(), [NetFramework.mscorlib, r1]); + var c2 = (Compilation)CS.CSharpCompilation.Create("comp2", Array.Empty(), [NetFramework.mscorlib, r2]); var type1 = (ITypeSymbol)c1.GlobalNamespace.GetMembers("C").Single(); var type2 = (ITypeSymbol)c2.GlobalNamespace.GetMembers("C").Single(); - var identityComparer = new SymbolEquivalenceComparer(AssemblySymbolIdentityComparer.Instance, distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true); + var identityComparer = new SymbolEquivalenceComparer(AssemblySymbolIdentityComparer.Instance, distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); var f1 = type1.GetMembers("F"); var f2 = type2.GetMembers("F"); diff --git a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb index 7f13cfe814d6d..fcb96e630d4fb 100644 --- a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb +++ b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb @@ -76,7 +76,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - CodeActionOptions.DefaultProvider, CancellationToken.None) Assert.Equal(0, fixes.Count()) @@ -92,7 +91,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - CodeActionOptions.DefaultProvider, CancellationToken.None) Assert.Equal(1, fixes.Count()) @@ -102,7 +100,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - CodeActionOptions.DefaultProvider, CancellationToken.None) Assert.Equal(0, fixes.Count()) @@ -151,7 +148,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - CodeActionOptions.DefaultProvider, CancellationToken.None) Assert.Equal(0, fixes.Count()) @@ -167,7 +163,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - CodeActionOptions.DefaultProvider, CancellationToken.None) Assert.Equal(0, fixes.Count()) @@ -299,7 +294,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests ' Make sure we don't crash Dim unused = Await codefixService.GetMostSevereFixAsync( - document, Text.TextSpan.FromBounds(0, 0), New DefaultCodeActionRequestPriorityProvider(), CodeActionOptions.DefaultProvider, CancellationToken.None) + document, Text.TextSpan.FromBounds(0, 0), New DefaultCodeActionRequestPriorityProvider(), CancellationToken.None) End Using End Function diff --git a/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb b/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb index cdd0c8d1cb616..dbd1782c5984a 100644 --- a/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb +++ b/src/EditorFeatures/Test2/Expansion/AbstractExpansionTest.vb @@ -5,10 +5,8 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeCleanup Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Text @@ -30,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Expansion Dim root = Await document.GetSyntaxRootAsync() - Dim cleanupOptions = CodeCleanupOptions.GetDefault(document.Project.Services) + Dim cleanupOptions = Await document.GetCodeCleanupOptionsAsync(CancellationToken.None) Dim spans As ImmutableArray(Of TextSpan) = Nothing If hostDocument.AnnotatedSpans.TryGetValue("Expand", spans) Then diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb index 772f5592595f0..34b4b0a45eb19 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb @@ -12597,6 +12597,30 @@ $$ End Using End Function + + + Public Async Function ReferenceToMethodThatFollow(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + + class C + { + void M() + { + if (true) + { + this.Sw$$ + + private void SwitchColor() { } + } + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.CSharp12) + + state.SendInvokeCompletionList() + Await state.AssertCompletionSession() + Await state.AssertCompletionItemsContain("SwitchColor", displayTextSuffix:="") + End Using + End Function + Public Async Function TestCompletionInExtensionForType1(showCompletionInArgumentLists As Boolean) As Task Using state = TestStateFactory.CreateCSharpTestState( diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb index af3cd6bf283be..6b08bb5c7309f 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb @@ -10,7 +10,6 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense <[UseExportProvider]> Public Class CSharpSignatureHelpCommandHandlerTests - Public Async Function TestCreateAndDismiss(showCompletionInArgumentLists As Boolean) As Task Using state = TestStateFactory.CreateCSharpTestState( @@ -931,6 +930,31 @@ class C End Using End Function + + + + + Public Async Function TestParameterIndexBeyondSyntacticIndex(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +class C +{ + void Main() + { + M(0, d$$) + } + + void M(int a, int b = 0, int c = 0, int d = 0) { } +} + , showCompletionInArgumentLists:=showCompletionInArgumentLists) + + state.SendInvokeSignatureHelp() + Await state.AssertSelectedSignatureHelpItem(displayText:="void C.M(int a, int b = 0, int c = 0, int d = 0)", selectedParameter:="int b = 0") + state.SendTypeChars(":") + Await state.AssertSelectedSignatureHelpItem(displayText:="void C.M(int a, int b = 0, int c = 0, int d = 0)", selectedParameter:="int d = 0") + End Using + End Function + ' SemanticModel.GetMemberGroup doesn't work for extension members yet. Public Async Function TypingUpdatesParameters_ExtensionType1(showCompletionInArgumentLists As Boolean) As Task diff --git a/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb b/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb index 21e47ea01dc99..0b99ed7563aa2 100644 --- a/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb @@ -87,7 +87,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense slowProvider.Setup(Function(p) p.IsTriggerCharacter(" "c)).Returns(True) slowProvider.Setup(Function(p) p.IsRetriggerCharacter(" "c)).Returns(True) slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _ - .Returns(Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, argumentIndex:=0, argumentCount:=0, argumentName:=Nothing))) + .Returns(Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing))) Dim controller = CreateController(CreateWorkspace(), provider:=slowProvider.Object, waitForPresentation:=True) ' Now force an update to the model that will result in stopping the session @@ -115,7 +115,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _ .Returns(Function() mre.WaitOne() - Return Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, argumentIndex:=0, argumentCount:=0, argumentName:=Nothing)) + Return Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing)) End Function) GetMocks(controller).PresenterSession.Setup(Sub(p) p.Dismiss()) @@ -135,7 +135,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _ .Returns(Function() mre.WaitOne() - Return Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, argumentIndex:=0, argumentCount:=0, argumentName:=Nothing)) + Return Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing)) End Function) GetMocks(controller).PresenterSession.Setup(Sub(p) p.Dismiss()) @@ -157,7 +157,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense slowProvider.Setup(Function(p) p.IsTriggerCharacter(" "c)).Returns(True) slowProvider.Setup(Function(p) p.IsRetriggerCharacter(" "c)).Returns(True) slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _ - .Returns(Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, argumentIndex:=0, argumentCount:=0, argumentName:=Nothing))) + .Returns(Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing))) Await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync() Dim controller = CreateController(workspace, provider:=slowProvider.Object, waitForPresentation:=True) @@ -168,7 +168,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _ .Returns(Function() checkpoint.Task.Wait() - Return Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 2), selectedItem:=0, argumentIndex:=0, argumentCount:=0, argumentName:=Nothing)) + Return Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 2), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing)) End Function) Await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync() @@ -355,7 +355,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Public Function GetItemsAsync(document As Document, position As Integer, triggerInfo As SignatureHelpTriggerInfo, options As MemberDisplayOptions, cancellationToken As CancellationToken) As Task(Of SignatureHelpItems) Implements ISignatureHelpProvider.GetItemsAsync GetItemsCount += 1 Return Task.FromResult(If(_items.Any(), - New SignatureHelpItems(_items, TextSpan.FromBounds(position, position), selectedItem:=0, argumentIndex:=0, argumentCount:=0, argumentName:=Nothing), + New SignatureHelpItems(_items, TextSpan.FromBounds(position, position), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing), Nothing)) End Function diff --git a/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb index 90a10e6bd54b0..4550fce1c2846 100644 --- a/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb @@ -1403,7 +1403,7 @@ End Class End Using End Function - + Public Async Function CompletionUpAfterLeftCurlyBrace() As Task Using state = TestStateFactory.CreateVisualBasicTestState( @@ -1424,7 +1424,7 @@ End Class End Using End Function - + Public Async Function CompletionUpAfterLeftAngleBracket() As Task Using state = TestStateFactory.CreateVisualBasicTestState( @@ -1653,7 +1653,7 @@ End Class End Function - + Public Sub TabAfterNullableFollowedByQuestionMark() Using state = TestStateFactory.CreateVisualBasicTestState( : TestB protected bool? HideAdvancedMembers { get; set; } protected bool? ShowNameSuggestions { get; set; } protected bool? ShowNewSnippetExperience { get; set; } + protected bool? TriggerOnDeletion { get; set; } protected AbstractCompletionProviderTests() { @@ -78,6 +79,9 @@ private CompletionOptions GetCompletionOptions() if (ShowNewSnippetExperience.HasValue) options = options with { ShowNewSnippetExperienceUserOption = ShowNewSnippetExperience.Value }; + if (TriggerOnDeletion.HasValue) + options = options with { TriggerOnDeletion = TriggerOnDeletion.Value }; + return options; } @@ -114,7 +118,7 @@ internal static ImmutableHashSet GetRoles(Document document) private protected abstract 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, bool? isComplexTextEdit, List matchingFilters, CompletionItemFlags? flags, CompletionOptions options, @@ -131,6 +135,7 @@ internal Task GetCompletionListAsync( private protected async Task CheckResultsAsync( Document document, int position, string expectedItemOrNull, string expectedDescriptionOrNull, bool usePreviousCharAsTrigger, + char? deletedCharTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionModeItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription, @@ -149,6 +154,10 @@ private protected async Task CheckResultsAsync( { trigger = RoslynCompletion.CompletionTrigger.CreateInsertionTrigger(insertedCharacter: code.ElementAt(position - 1)); } + else if (deletedCharTrigger.HasValue) + { + trigger = RoslynCompletion.CompletionTrigger.CreateDeletionTrigger(deletedCharacter: deletedCharTrigger.Value); + } var displayOptions = SymbolDescriptionOptions.Default; var completionService = GetCompletionService(document.Project); @@ -232,7 +241,7 @@ private static bool FiltersMatch(List expectedMatchingFilters, private async Task VerifyAsync( string markup, string expectedItemOrNull, string expectedDescriptionOrNull, - SourceCodeKind? sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, + SourceCodeKind? sourceCodeKind, bool usePreviousCharAsTrigger, char? deletedCharTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionModeItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, List matchingFilters, CompletionItemFlags? flags, CompletionOptions options, bool skipSpeculation = false) @@ -250,7 +259,7 @@ private async Task VerifyAsync( await VerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, - sourceKind, usePreviousCharAsTrigger, checkForAbsence, glyph, + sourceKind, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionModeItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options, skipSpeculation: skipSpeculation).ConfigureAwait(false); @@ -326,14 +335,14 @@ protected virtual IEqualityComparer GetStringComparer() private protected async Task VerifyItemExistsAsync( string markup, string expectedItem, string expectedDescriptionOrNull = null, - SourceCodeKind? sourceCodeKind = null, bool usePreviousCharAsTrigger = false, + SourceCodeKind? sourceCodeKind = null, bool usePreviousCharAsTrigger = false, char? deletedCharTrigger = null, int? glyph = null, int? matchPriority = null, bool? hasSuggestionModeItem = null, string displayTextSuffix = null, string displayTextPrefix = null, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null, CompletionOptions options = null, bool skipSpeculation = false) { await VerifyAsync(markup, expectedItem, expectedDescriptionOrNull, - sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence: false, + sourceCodeKind, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence: false, glyph: glyph, matchPriority: matchPriority, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, @@ -343,26 +352,26 @@ await VerifyAsync(markup, expectedItem, expectedDescriptionOrNull, private protected async Task VerifyItemIsAbsentAsync( string markup, string expectedItem, string expectedDescriptionOrNull = null, - SourceCodeKind? sourceCodeKind = null, bool usePreviousCharAsTrigger = false, + SourceCodeKind? sourceCodeKind = null, bool usePreviousCharAsTrigger = false, char? deletedCharTrigger = null, bool? hasSuggestionModeItem = null, string displayTextSuffix = null, string displayTextPrefix = null, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null, CompletionOptions options = null) { await VerifyAsync(markup, expectedItem, expectedDescriptionOrNull, sourceCodeKind, - usePreviousCharAsTrigger, checkForAbsence: true, glyph: null, matchPriority: null, + usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence: true, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, isComplexTextEdit: isComplexTextEdit, matchingFilters: matchingFilters, flags: flags, options); } private protected async Task VerifyAnyItemExistsAsync( - string markup, SourceCodeKind? sourceCodeKind = null, bool usePreviousCharAsTrigger = false, + string markup, SourceCodeKind? sourceCodeKind = null, bool usePreviousCharAsTrigger = false, char? deletedCharTrigger = null, bool? hasSuggestionModeItem = null, string displayTextSuffix = null, string displayTextPrefix = null, string inlineDescription = null, CompletionOptions options = null) { await VerifyAsync(markup, expectedItemOrNull: null, expectedDescriptionOrNull: null, - sourceCodeKind, usePreviousCharAsTrigger: usePreviousCharAsTrigger, + sourceCodeKind, usePreviousCharAsTrigger: usePreviousCharAsTrigger, deletedCharTrigger: deletedCharTrigger, checkForAbsence: false, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, @@ -376,7 +385,7 @@ private protected async Task VerifyNoItemsExistAsync( { await VerifyAsync( markup, expectedItemOrNull: null, expectedDescriptionOrNull: null, - sourceCodeKind, usePreviousCharAsTrigger: usePreviousCharAsTrigger, + sourceCodeKind, usePreviousCharAsTrigger: usePreviousCharAsTrigger, deletedCharTrigger: null, checkForAbsence: true, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, displayTextPrefix: null, inlineDescription: inlineDescription, @@ -397,7 +406,7 @@ private protected virtual async Task VerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, - bool usePreviousCharAsTrigger, bool checkForAbsence, + bool usePreviousCharAsTrigger, char? deletedCharTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionModeItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, @@ -412,7 +421,7 @@ private protected virtual async Task VerifyWorkerAsync( await CheckResultsAsync( document1, position, expectedItemOrNull, - expectedDescriptionOrNull, usePreviousCharAsTrigger, + expectedDescriptionOrNull, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionModeItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); @@ -422,7 +431,7 @@ await CheckResultsAsync( var document2 = workspaceFixture.Target.UpdateDocument(code, sourceCodeKind, cleanBeforeUpdate: false); await CheckResultsAsync( document2, position, expectedItemOrNull, expectedDescriptionOrNull, - usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, + usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionModeItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); } @@ -905,7 +914,7 @@ protected async Task VerifyItemInLinkedFilesAsync(string xmlString, string expec } private protected async Task VerifyAtPositionAsync( - 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, @@ -917,13 +926,13 @@ private protected async Task VerifyAtPositionAsync( await BaseVerifyWorkerAsync(code, position, expectedItemOrNull, expectedDescriptionOrNull, - sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, + sourceCodeKind, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options, skipSpeculation: skipSpeculation); } private protected async Task VerifyAtPositionAsync( - 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, @@ -931,14 +940,14 @@ private protected async Task VerifyAtPositionAsync( List matchingFilters = null, CompletionItemFlags? flags = null, CompletionOptions options = null, bool skipSpeculation = false) { await VerifyAtPositionAsync( - code, position, string.Empty, usePreviousCharAsTrigger, + code, position, string.Empty, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options, skipSpeculation: skipSpeculation); } private protected async Task VerifyAtEndOfFileAsync( - 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, @@ -957,13 +966,13 @@ private protected async Task VerifyAtEndOfFileAsync( await BaseVerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, - sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, + sourceCodeKind, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); } private protected async Task VerifyAtPosition_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, @@ -972,7 +981,7 @@ private protected async Task VerifyAtPosition_ItemPartiallyWrittenAsync( CompletionOptions options = null, bool skipSpeculation = false) { await VerifyAtPositionAsync( - code, position, ItemPartiallyWritten(expectedItemOrNull), usePreviousCharAsTrigger, + code, position, ItemPartiallyWritten(expectedItemOrNull), usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options, @@ -980,7 +989,7 @@ await VerifyAtPositionAsync( } private protected async Task VerifyAtEndOfFileAsync( - 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, @@ -988,14 +997,14 @@ private protected async Task VerifyAtEndOfFileAsync( List matchingFilters = null, CompletionItemFlags? flags = null, CompletionOptions options = null) { - await VerifyAtEndOfFileAsync(code, position, string.Empty, usePreviousCharAsTrigger, + await VerifyAtEndOfFileAsync(code, position, string.Empty, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); } private protected async Task VerifyAtEndOfFile_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, @@ -1004,7 +1013,7 @@ private protected async Task VerifyAtEndOfFile_ItemPartiallyWrittenAsync( CompletionOptions options = null) { await VerifyAtEndOfFileAsync( - code, position, ItemPartiallyWritten(expectedItemOrNull), usePreviousCharAsTrigger, + code, position, ItemPartiallyWritten(expectedItemOrNull), usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); @@ -1075,7 +1084,7 @@ protected async Task VerifyCommonCommitCharactersAsync(string initialMarkup, str protected async Task VerifyCommitCharactersAsync(string initialMarkup, string textTypedSoFar, char[] validChars, char[] invalidChars = null, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular) { Assert.NotNull(validChars); - invalidChars ??= new[] { 'x' }; + invalidChars ??= ['x']; using var workspace = CreateWorkspace(initialMarkup); var hostDocument = workspace.DocumentWithCursor; diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs b/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs index 17acbf67cd762..f78dc19aca163 100644 --- a/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs +++ b/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticTaggerWrapper.cs @@ -38,7 +38,7 @@ public DiagnosticTaggerWrapper( _listenerProvider = workspace.GetService(); var analyzerReference = new TestAnalyzerReferenceByLanguage(analyzerMap ?? DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap()); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); // Change the background analysis scope to OpenFiles instead of ActiveFile (default), // so that every diagnostic tagger test does not need to mark test files as "active" file. diff --git a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs index 441ac828ce5b6..206227baa5c13 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/AbstractNewDocumentFormattingServiceTests.cs @@ -32,7 +32,7 @@ internal async Task TestAsync(string testCode, string expected, OptionsCollectio var cleanupOptions = options?.GetCodeCleanupOptions(languageServices, allowImportsInHiddenRegions: false) ?? - CodeCleanupOptions.GetDefault(languageServices); + await document.GetCodeCleanupOptionsAsync(CancellationToken.None); var formattingService = document.GetRequiredLanguageService(); var formattedDocument = await formattingService.FormatNewDocumentAsync(document, hintDocument: null, cleanupOptions, CancellationToken.None); diff --git a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs b/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs index 9adfa5d854611..ab040589da27e 100644 --- a/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs +++ b/src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs @@ -42,7 +42,7 @@ namespace Roslyn.Test.Utilities [UseExportProvider] public abstract partial class AbstractLanguageServerProtocolTests { - private static readonly SystemTextJsonFormatter s_messageFormatter = RoslynLanguageServer.CreateJsonMessageFormatter(); + protected static readonly JsonSerializerOptions JsonSerializerOptions = RoslynLanguageServer.CreateJsonMessageFormatter().JsonSerializerOptions; private protected readonly AbstractLspLogger TestOutputLspLogger; protected AbstractLanguageServerProtocolTests(ITestOutputHelper? testOutputHelper) @@ -124,8 +124,8 @@ private protected static LSP.ClientCapabilities GetCapabilities(bool isVS) /// the actual object to be converted to JSON. public static void AssertJsonEquals(T1 expected, T2 actual) { - var expectedStr = JsonSerializer.Serialize(expected, s_messageFormatter.JsonSerializerOptions); - var actualStr = JsonSerializer.Serialize(actual, s_messageFormatter.JsonSerializerOptions); + var expectedStr = JsonSerializer.Serialize(expected, JsonSerializerOptions); + var actualStr = JsonSerializer.Serialize(actual, JsonSerializerOptions); AssertEqualIgnoringWhitespace(expectedStr, actualStr); } @@ -133,7 +133,7 @@ protected static void AssertEqualIgnoringWhitespace(string expected, string actu { var expectedWithoutWhitespace = Regex.Replace(expected, @"\s+", string.Empty); var actualWithoutWhitespace = Regex.Replace(actual, @"\s+", string.Empty); - Assert.Equal(expectedWithoutWhitespace, actualWithoutWhitespace); + AssertEx.Equal(expectedWithoutWhitespace, actualWithoutWhitespace); } /// @@ -181,6 +181,7 @@ internal static LSP.SymbolInformation CreateSymbolInformation(LSP.SymbolKind kin { var imageId = glyph.GetImageId(); +#pragma warning disable CS0618 // SymbolInformation is obsolete, need to switch to DocumentSymbol/WorkspaceSymbol var info = new LSP.VSSymbolInformation() { Kind = kind, @@ -191,6 +192,7 @@ internal static LSP.SymbolInformation CreateSymbolInformation(LSP.SymbolKind kin if (containerName != null) info.ContainerName = containerName; +#pragma warning restore CS0618 return info; } @@ -269,7 +271,7 @@ private protected static LSP.CompletionParams CreateCompletionParams( SortText = sortText, InsertTextFormat = LSP.InsertTextFormat.Plaintext, Kind = kind, - Data = JsonSerializer.SerializeToElement(new CompletionResolveData(resultId, ProtocolConversions.DocumentToTextDocumentIdentifier(document)), s_messageFormatter.JsonSerializerOptions), + Data = JsonSerializer.SerializeToElement(new CompletionResolveData(resultId, ProtocolConversions.DocumentToTextDocumentIdentifier(document)), JsonSerializerOptions), Preselect = preselect, VsResolveTextEditOnCommit = vsResolveTextEditOnCommit, LabelDetails = labelDetails @@ -349,7 +351,7 @@ private async Task CreateTestLspServerAsync(EditorTestWorkspace w if (initializationOptions.AdditionalAnalyzers != null) analyzerReferencesByLanguage = analyzerReferencesByLanguage.WithAdditionalAnalyzers(languageName, initializationOptions.AdditionalAnalyzers); - solution = solution.WithAnalyzerReferences(new[] { analyzerReferencesByLanguage }); + solution = solution.WithAnalyzerReferences([analyzerReferencesByLanguage]); await workspace.ChangeSolutionAsync(solution); // Important: We must wait for workspace creation operations to finish. @@ -371,7 +373,7 @@ private protected async Task CreateXmlTestLspServerAsync( var workspace = CreateWorkspace(lspOptions, workspaceKind, mutatingLspWorkspace); workspace.InitializeDocuments(XElement.Parse(xmlContent), openDocuments: false); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { CreateTestAnalyzersReference() })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([CreateTestAnalyzersReference()])); // 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 @@ -642,6 +644,11 @@ public Task ExecuteNotification0Async(string methodName) return _clientRpc.NotifyWithParameterObjectAsync(methodName); } + public Task ExecutePreSerializedRequestAsync(string methodName, JsonDocument serializedRequest) + { + return _clientRpc.InvokeWithParameterObjectAsync(methodName, serializedRequest); + } + public async Task OpenDocumentAsync(Uri documentUri, string? text = null, string languageId = "") { if (text == null) diff --git a/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs b/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs index 0787f62e4900a..df48af1b2af08 100644 --- a/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs +++ b/src/EditorFeatures/TestUtilities/Rename/RenamerTests.cs @@ -47,7 +47,7 @@ protected async Task TestRenameDocument( solution = solution .AddProject(projectInfo); - var remainingErrors = new HashSet(expectedErrors ?? new string[0]); + var remainingErrors = new HashSet(expectedErrors ?? []); for (var i = 0; i < startDocuments.Length; i++) { diff --git a/src/EditorFeatures/TestUtilities/RenameTracking/MockRefactorNotifyService.cs b/src/EditorFeatures/TestUtilities/RenameTracking/MockRefactorNotifyService.cs index 778f369aba5b2..d920ae0d340bc 100644 --- a/src/EditorFeatures/TestUtilities/RenameTracking/MockRefactorNotifyService.cs +++ b/src/EditorFeatures/TestUtilities/RenameTracking/MockRefactorNotifyService.cs @@ -11,10 +11,9 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.RenameTracking { public sealed class MockRefactorNotifyService : IRefactorNotifyService { - private int _onBeforeSymbolRenamedCount = 0; private int _onAfterSymbolRenamedCount = 0; - public int OnBeforeSymbolRenamedCount { get { return _onBeforeSymbolRenamedCount; } } + public int OnBeforeSymbolRenamedCount { get; private set; } = 0; public int OnAfterSymbolRenamedCount { get { return _onAfterSymbolRenamedCount; } } public bool OnBeforeSymbolRenamedReturnValue { get; set; } @@ -22,7 +21,7 @@ public sealed class MockRefactorNotifyService : IRefactorNotifyService public bool TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, ISymbol symbol, string newName, bool throwOnFailure) { - _onBeforeSymbolRenamedCount++; + OnBeforeSymbolRenamedCount++; if (throwOnFailure && !OnBeforeSymbolRenamedReturnValue) { diff --git a/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs b/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs index 225d2a46e9992..9579792d57ff5 100644 --- a/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs @@ -159,7 +159,7 @@ protected virtual async Task VerifyCurrentParameterNameAsync(string markup, stri private static async Task GetArgumentStateAsync(int cursorPosition, Document document, ISignatureHelpProvider signatureHelpProvider, SignatureHelpTriggerInfo triggerInfo, MemberDisplayOptions options) { var items = await signatureHelpProvider.GetItemsAsync(document, cursorPosition, triggerInfo, options, CancellationToken.None); - return items == null ? null : new SignatureHelpState(items.ArgumentIndex, items.ArgumentCount, items.ArgumentName, argumentNames: default); + return items == null ? null : new SignatureHelpState(items.SemanticParameterIndex, items.SyntacticArgumentCount, items.ArgumentName, ArgumentNames: default); } private async Task VerifyCurrentParameterNameWorkerAsync(string markup, string expectedParameterName, SourceCodeKind sourceCodeKind) @@ -237,7 +237,7 @@ private static void CompareSigHelpItemsAndCurrentPosition( if (expectedTestItem.CurrentParameterIndex != null) { - Assert.True(expectedTestItem.CurrentParameterIndex == items.ArgumentIndex, $"The current parameter is {items.ArgumentIndex}, but we expected {expectedTestItem.CurrentParameterIndex}"); + Assert.True(expectedTestItem.CurrentParameterIndex == items.SemanticParameterIndex, $"The current parameter is {items.SemanticParameterIndex}, but we expected {expectedTestItem.CurrentParameterIndex}"); } if (expectedTestItem.Description != null) diff --git a/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxNodeStructureProviderTests.cs b/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxNodeStructureProviderTests.cs index 835eef1fa60f4..239e5692b2e79 100644 --- a/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxNodeStructureProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxNodeStructureProviderTests.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Structure; using Xunit; @@ -41,10 +42,10 @@ internal sealed override async Task> GetBlockSpansWork } var outliner = CreateProvider(); - using var actualRegions = TemporaryArray.Empty; + using var _ = ArrayBuilder.GetInstance(out var actualRegions); // Calculate previousToken for tests the same way it is derived in production code var previousToken = root.DescendantNodesAndTokens(descendIntoTrivia: true).TakeWhile(nodeOrToken => nodeOrToken != node).LastOrDefault(nodeOrToken => nodeOrToken.IsToken).AsToken(); - outliner.CollectBlockSpans(previousToken, node, ref actualRegions.AsRef(), options, CancellationToken.None); + outliner.CollectBlockSpans(previousToken, node, actualRegions, options, CancellationToken.None); // TODO: Determine why we get null outlining spans. return actualRegions.ToImmutableAndClear(); diff --git a/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxTriviaStructureProviderTests.cs b/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxTriviaStructureProviderTests.cs index 498ee5a0584ee..c678acd1b4253 100644 --- a/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxTriviaStructureProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Structure/AbstractSyntaxTriviaStructureProviderTests.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Structure; @@ -22,8 +23,8 @@ internal sealed override async Task> GetBlockSpansWork var trivia = root.FindTrivia(position, findInsideTrivia: true); var outliner = CreateProvider(); - using var actualRegions = TemporaryArray.Empty; - outliner.CollectBlockSpans(trivia, ref actualRegions.AsRef(), options, CancellationToken.None); + using var _ = ArrayBuilder.GetInstance(out var actualRegions); + outliner.CollectBlockSpans(trivia, actualRegions, options, CancellationToken.None); // TODO: Determine why we get null outlining spans. return actualRegions.ToImmutableAndClear(); diff --git a/src/EditorFeatures/TestUtilities/TestExtensionErrorHandler.cs b/src/EditorFeatures/TestUtilities/TestExtensionErrorHandler.cs index c381a0ba1e507..fb7d6e162fed6 100644 --- a/src/EditorFeatures/TestUtilities/TestExtensionErrorHandler.cs +++ b/src/EditorFeatures/TestUtilities/TestExtensionErrorHandler.cs @@ -17,9 +17,7 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests [Export(typeof(ITestErrorHandler))] internal class TestExtensionErrorHandler : IExtensionErrorHandler, ITestErrorHandler { - private ImmutableList _exceptions = ImmutableList.Empty; - - public ImmutableList Exceptions => _exceptions; + public ImmutableList Exceptions { get; private set; } = ImmutableList.Empty; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -54,7 +52,7 @@ public void HandleError(object sender, Exception exception) // fail. Unfortuntately throwing an exception here is not going to help because // the editor is going to catch and swallow it. Store it here and wait for the // containing workspace to notice it and throw. - _exceptions = _exceptions.Add(exception); + Exceptions = Exceptions.Add(exception); } } } diff --git a/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace_Create.cs b/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace_Create.cs index 482d8619dcf68..01f9804a38455 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace_Create.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/EditorTestWorkspace_Create.cs @@ -46,7 +46,7 @@ internal static EditorTestWorkspace Create( ParseOptions parseOptions, string content) { - return Create(language, compilationOptions, parseOptions, new[] { content }); + return Create(language, compilationOptions, parseOptions, [content]); } /// @@ -60,7 +60,7 @@ internal static EditorTestWorkspace Create( ParseOptions parseOptions, string content) { - return Create(workspaceKind, language, compilationOptions, parseOptions, new[] { content }); + return Create(workspaceKind, language, compilationOptions, parseOptions, [content]); } /// Can pass in multiple file contents: files will be named test1.cs, test2.cs, etc. diff --git a/src/EditorFeatures/VisualBasicTest/AutomaticCompletion/AutomaticLineEnderTests.vb b/src/EditorFeatures/VisualBasicTest/AutomaticCompletion/AutomaticLineEnderTests.vb index 8940d2ca9f33b..a03d3c22cf3cd 100644 --- a/src/EditorFeatures/VisualBasicTest/AutomaticCompletion/AutomaticLineEnderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/AutomaticCompletion/AutomaticLineEnderTests.vb @@ -100,7 +100,7 @@ End Class) End Sub - + Public Sub TestDim3() Test(Class C Sub Method() diff --git a/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb b/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb index da3fe27a072e4..eaca1431049d9 100644 --- a/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/CaseCorrecting/CaseCorrectionServiceTests.vb @@ -34,7 +34,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CaseCorrecting Dim document = workspace.CurrentSolution.GetDocument(hostDocument.Id) Dim span = (Await document.GetSyntaxRootAsync()).FullSpan - Dim options = CodeCleanupOptions.GetDefault(document.Project.Services) + Dim options = Await document.GetCodeCleanupOptionsAsync(CancellationToken.None) Dim service = document.GetLanguageService(Of ICodeCleanerService) Dim newDocument = Await service.CleanupAsync( diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb index 66ea18759f86c..3d1737bdf71b2 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb @@ -26,13 +26,13 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Private Protected Overrides Function BaseVerifyWorkerAsync( code As String, position As Integer, expectedItemOrNull As String, expectedDescriptionOrNull As String, - sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, + sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, deletedCharTrigger As Char?, checkForAbsence As Boolean, glyph As Integer?, matchPriority As Integer?, hasSuggestionItem As Boolean?, displayTextSuffix As String, displayTextPrefix As String, inlineDescription As String, isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?, options As CompletionOptions, Optional skipSpeculation As Boolean = False) As Task Return MyBase.VerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, - sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, + sourceCodeKind, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options, skipSpeculation) End Function @@ -40,7 +40,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Private Protected Overrides Async Function VerifyWorkerAsync( code As String, position As Integer, expectedItemOrNull As String, expectedDescriptionOrNull As String, - sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, + sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, deletedCharTrigger As Char?, checkForAbsence As Boolean, glyph As Integer?, matchPriority As Integer?, hasSuggestionItem As Boolean?, displayTextSuffix As String, displayTextPrefix As String, inlineDescription As String, isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?, options As CompletionOptions, Optional skipSpeculation As Boolean = False) As Task @@ -51,12 +51,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet End If 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, skipSpeculation) 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) @@ -64,12 +64,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet ' or if we're verifying that the list will show up (without specifying an actual item) If Not checkForAbsence AndAlso expectedItemOrNull <> Nothing Then 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:=Nothing, options, skipSpeculation:=skipSpeculation) 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:=Nothing, options) End If diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb index b94951bf168c7..1f20bd2471455 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb @@ -16,7 +16,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Private Protected Overrides Async Function VerifyWorkerAsync( code As String, position As Integer, expectedItemOrNull As String, expectedDescriptionOrNull As String, - sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, + sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, deletedCharTrigger As Char?, checkForAbsence As Boolean, glyph As Integer?, matchPriority As Integer?, hasSuggestionItem As Boolean?, displayTextSuffix As String, displayTextPrefix As String, inlineDescription As String, isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?, @@ -29,7 +29,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Await BaseVerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, - sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, + sourceCodeKind, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options, skipSpeculation) End Function diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb index 8f3d04fa10b09..d55e1f46ff1ed 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb @@ -561,7 +561,7 @@ End Class.Value Dim position As Integer MarkupTestFile.GetPosition(markup.NormalizeLineEndings(), code, position) - Await BaseVerifyWorkerAsync(code, position, "[Class]()", "Sub CBase.Class()", SourceCodeKind.Regular, False, False, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing) + Await BaseVerifyWorkerAsync(code, position, "[Class]()", "Sub CBase.Class()", SourceCodeKind.Regular, False, deletedCharTrigger:=Nothing, False, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing) End Function @@ -582,7 +582,7 @@ End Class.Value Await BaseVerifyWorkerAsync( code, position, "[Class]", "Property CBase.Class As Integer", - SourceCodeKind.Regular, False, False, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing) + SourceCodeKind.Regular, False, deletedCharTrigger:=Nothing, False, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing) End Function diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb index 4af4ecf9a3460..8f58a5e1656a2 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb @@ -1362,7 +1362,7 @@ Class C ' explicitly test only the "nothing typed" case. ' This is also the Dev12 behavior for suggesting labels. Await VerifyAtPositionAsync( - text, position, usePreviousCharAsTrigger:=True, + text, position, usePreviousCharAsTrigger:=True, deletedCharTrigger:=Nothing, expectedItemOrNull:="10", expectedDescriptionOrNull:=Nothing, sourceCodeKind:=SourceCodeKind.Regular, checkForAbsence:=False, glyph:=Nothing, matchPriority:=Nothing, hasSuggestionItem:=Nothing, @@ -7654,10 +7654,10 @@ End Namespace Using workspace = EditorTestWorkspace.Create(input, composition:=GetComposition()) Dim document = workspace.CurrentSolution.GetDocument(workspace.DocumentWithCursor.Id) Dim position = workspace.DocumentWithCursor.CursorPosition.Value - Await CheckResultsAsync(document, position, "InstanceMethod", expectedDescriptionOrNull:=Nothing, usePreviousCharAsTrigger:=False, checkForAbsence:=False, + Await CheckResultsAsync(document, position, "InstanceMethod", expectedDescriptionOrNull:=Nothing, usePreviousCharAsTrigger:=False, deletedCharTrigger:=Nothing, checkForAbsence:=False, glyph:=Nothing, matchPriority:=Nothing, hasSuggestionModeItem:=Nothing, displayTextSuffix:=Nothing, displayTextPrefix:=Nothing, inlineDescription:=Nothing, isComplexTextEdit:=Nothing, matchingFilters:=Nothing, flags:=Nothing, options:=Nothing) - Await CheckResultsAsync(document, position, "SharedMethod", expectedDescriptionOrNull:=Nothing, usePreviousCharAsTrigger:=False, checkForAbsence:=False, + Await CheckResultsAsync(document, position, "SharedMethod", expectedDescriptionOrNull:=Nothing, usePreviousCharAsTrigger:=False, deletedCharTrigger:=Nothing, checkForAbsence:=False, glyph:=Nothing, matchPriority:=Nothing, hasSuggestionModeItem:=Nothing, displayTextSuffix:=Nothing, displayTextPrefix:=Nothing, inlineDescription:=Nothing, isComplexTextEdit:=Nothing, matchingFilters:=Nothing, flags:=Nothing, options:=Nothing) End Using diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb index a4dc59fd809d3..fd2787213ceaa 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb @@ -20,14 +20,14 @@ Namespace Tests Private Protected Overrides Async Function VerifyWorkerAsync( code As String, position As Integer, expectedItemOrNull As String, expectedDescriptionOrNull As String, - sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, + sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, deletedCharTrigger As Char?, checkForAbsence As Boolean, glyph As Integer?, matchPriority As Integer?, hasSuggestionItem As Boolean?, displayTextSuffix As String, displayTextPrefix As String, inlineDescription As String, isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?, options As CompletionOptions, Optional skipSpeculation As Boolean = False) As Task - Await VerifyAtPositionAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options, skipSpeculation) - Await VerifyAtEndOfFileAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options) + Await VerifyAtPositionAsync(code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options, skipSpeculation) + Await VerifyAtEndOfFileAsync(code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options) End Function Private Async Function VerifyItemsExistAsync(markup As String, ParamArray items() As String) As Task @@ -957,5 +957,53 @@ end class" Await VerifyItemExistsAsync(text, "term") Await VerifyItemExistsAsync(text, "description") End Function + + + Public Async Function TriggerOnDeletion_DeleteInsideAttributeName() As Task + TriggerOnDeletion = True + + Dim text = " +''' +class C +end class" + Await VerifyItemExistsAsync(text, "langword", deletedCharTrigger:="w"c) + End Function + + + Public Async Function TriggerOnDeletion_DeleteInsideAttributeValue() As Task + TriggerOnDeletion = True + + Dim text = " +''' +class C +end class" + Await VerifyItemExistsAsync(text, "True", deletedCharTrigger:="r"c) + End Function + + + Public Async Function TriggerOnDeletion_DeleteInsideTagName() As Task + TriggerOnDeletion = True + + Dim text = " +''' +''' +class C +end class" + Await VerifyItemExistsAsync(text, "summary", deletedCharTrigger:="a"c) + End Function + + + Public Async Function TriggerOnDeletion_DeleteInXmlText_DoesntSuggest() As Task + TriggerOnDeletion = True + + Dim text = " +''' +''' a$$c +''' +class C +end class" + Await VerifyItemIsAbsentAsync(text, "see", deletedCharTrigger:="b"c) + End Function + End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CharacterTypingTests.vb b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CharacterTypingTests.vb index 8ac91a2698fc1..d00841abcb342 100644 --- a/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CharacterTypingTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EndConstructGeneration/CharacterTypingTests.vb @@ -31,7 +31,7 @@ End Class]]> endCaretPos:={3, 21}) End Sub - + Public Sub TestXmlEndConstructNotApplied() VerifyEndConstructNotAppliedAfterChar( before:= diff --git a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb index ef0e156145c7a..99ff3e546669a 100644 --- a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb +++ b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb @@ -106,8 +106,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ExtractMethod ' extract method Dim extractGenerationOptions = VBOptionsFactory.CreateExtractMethodGenerationOptions( - CodeGenerationOptions.GetDefault(document.Project.Services), - CodeCleanupOptions.GetDefault(document.Project.Services)) + Await document.GetCodeGenerationOptionsAsync(CancellationToken.None), + Await document.GetCodeCleanupOptionsAsync(CancellationToken.None)) Dim extractor = New VisualBasicMethodExtractor(selectedCode, extractGenerationOptions) Dim result = extractor.ExtractMethod(status, CancellationToken.None) diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb index 04ef58a719389..e2eff36a2a1c4 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb @@ -510,7 +510,6 @@ End Class Private Shared Async Function TestThirdPartyCodeFixer(Of TCodefix As {CodeFixProvider, New}, TAnalyzer As {DiagnosticAnalyzer, New})(expected As String, code As String, Optional severity As DiagnosticSeverity = DiagnosticSeverity.Warning) As Task Using workspace = TestWorkspace.CreateVisualBasic(code, composition:=EditorTestCompositions.EditorFeaturesWpf.AddParts(GetType(TCodefix))) - Dim options = CodeActionOptions.DefaultProvider Dim project = workspace.CurrentSolution.Projects.Single() Dim map = New Dictionary(Of String, ImmutableArray(Of DiagnosticAnalyzer)) From { @@ -540,7 +539,6 @@ End Class document, enabledDiagnostics, CodeAnalysisProgress.None, - options, CancellationToken.None) Dim actual = Await newDoc.GetTextAsync() @@ -588,7 +586,6 @@ End Class document, enabledDiagnostics, CodeAnalysisProgress.None, - workspace.GlobalOptions.CreateProvider(), CancellationToken.None) Dim actual = Await newDoc.GetTextAsync() diff --git a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb index 6443f03fd5b28..a59c2e7eeffb4 100644 --- a/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb +++ b/src/EditorFeatures/VisualBasicTest/LineCommit/CommitTestData.vb @@ -16,6 +16,7 @@ Imports Microsoft.CodeAnalysis.Text.Shared.Extensions Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Operations +Imports Microsoft.VisualStudio.Utilities Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.LineCommit Friend Class CommitTestData @@ -111,7 +112,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.LineCommit Throw New NotImplementedException() End Sub - Public Function CommitAsync(previewChanges As Boolean, cancellationToken As CancellationToken) As Task Implements IInlineRenameSession.CommitAsync + Public Function CommitAsync(previewChanges As Boolean, Optional editorOperationContext As IUIThreadOperationContext = Nothing) As Task Implements IInlineRenameSession.CommitAsync Throw New NotImplementedException() End Function End Class diff --git a/src/EditorFeatures/VisualBasicTest/Recommendations/RecommendationTestHelpers.vb b/src/EditorFeatures/VisualBasicTest/Recommendations/RecommendationTestHelpers.vb index 216471fd5ef8a..15f02976ee58c 100644 --- a/src/EditorFeatures/VisualBasicTest/Recommendations/RecommendationTestHelpers.vb +++ b/src/EditorFeatures/VisualBasicTest/Recommendations/RecommendationTestHelpers.vb @@ -31,7 +31,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Recommendations Dim parseOptions = New VisualBasicParseOptions().WithKind(kind) Dim tree = DirectCast(SyntaxFactory.ParseSyntaxTree(SourceText.From(source), parseOptions), VisualBasicSyntaxTree) - Dim comp = VisualBasicCompilation.Create("test", syntaxTrees:={tree}, references:={TestMetadata.Net451.mscorlib}) + Dim comp = VisualBasicCompilation.Create("test", syntaxTrees:={tree}, references:={NetFramework.mscorlib}) Dim semanticModel = comp.GetSemanticModel(tree) Dim context = VisualBasicSyntaxContext.CreateContext(document, semanticModel, position, CancellationToken.None) diff --git a/src/EditorFeatures/VisualBasicTest/SymbolId/SymbolKeyMetadataVsSourceTests.vb b/src/EditorFeatures/VisualBasicTest/SymbolId/SymbolKeyMetadataVsSourceTests.vb index 4efbeea3267f2..df2f6b8f76b8e 100644 --- a/src/EditorFeatures/VisualBasicTest/SymbolId/SymbolKeyMetadataVsSourceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/SymbolId/SymbolKeyMetadataVsSourceTests.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.SymbolId @@ -232,7 +233,7 @@ End Class - Dim comp20 = CreateEmptyCompilationWithReferences(src1, {TestMetadata.Net40.mscorlib}, TestOptions.ReleaseDll) + Dim comp20 = CreateEmptyCompilationWithReferences(src1, {Net40.References.mscorlib}, TestOptions.ReleaseDll) ' "Compilation 2 Assembly" Dim comp40 = CreateCompilationWithMscorlib40AndReferences(src2, {comp20.ToMetadataReference()}) @@ -306,7 +307,7 @@ End Class - Dim comp20 = CreateEmptyCompilationWithReferences(src1, {TestMetadata.Net40.mscorlib}, TestOptions.ReleaseDll) + Dim comp20 = CreateEmptyCompilationWithReferences(src1, {Net40.References.mscorlib}, TestOptions.ReleaseDll) ' Dim comp40 = CreateCompilationWithMscorlib40AndReferences(src2, {comp20.ToMetadataReference()}) @@ -382,7 +383,7 @@ End Class - Dim comp20 = CreateEmptyCompilationWithReferences(src1, {TestMetadata.Net40.mscorlib}, TestOptions.ReleaseDll) + Dim comp20 = CreateEmptyCompilationWithReferences(src1, {Net40.References.mscorlib}, TestOptions.ReleaseDll) Dim comp40 = CreateCompilationWithMscorlib40AndReferences(src2, {comp20.ToMetadataReference()}) Dim ver20Symbols = GetSourceSymbols(comp20, SymbolCategory.NonTypeMember).Where(Function(s) Not s.IsAccessor() And s.Kind <> SymbolKind.Parameter).OrderBy(Function(s) s.Name).ToList() diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EELocalSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EELocalSymbol.cs index 0031907173441..82665d5d9ef61 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EELocalSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EELocalSymbol.cs @@ -21,7 +21,6 @@ internal sealed class EELocalSymbol : EELocalSymbolBase private readonly bool _isCompilerGenerated; private readonly ImmutableArray _locations; private readonly string _nameOpt; - private readonly int _ordinal; // index in locals of containing block private readonly bool _isPinned; private readonly RefKind _refKind; private readonly bool _canScheduleToStack; @@ -61,7 +60,7 @@ public EELocalSymbol( _method = method; _locations = locations; _nameOpt = nameOpt; - _ordinal = ordinal; + Ordinal = ordinal; _declarationKind = declarationKind; _type = type; _refKind = refKind; @@ -73,7 +72,7 @@ public EELocalSymbol( internal override EELocalSymbolBase ToOtherMethod(MethodSymbol method, TypeMap typeMap) { var type = typeMap.SubstituteType(_type); - return new EELocalSymbol(method, _locations, _nameOpt, _ordinal, _declarationKind, type, _refKind, _isPinned, _isCompilerGenerated, _canScheduleToStack); + return new EELocalSymbol(method, _locations, _nameOpt, Ordinal, _declarationKind, type, _refKind, _isPinned, _isCompilerGenerated, _canScheduleToStack); } internal override LocalDeclarationKind DeclarationKind @@ -86,10 +85,7 @@ internal override bool CanScheduleToStack get { return _canScheduleToStack; } } - internal int Ordinal - { - get { return _ordinal; } - } + internal int Ordinal { get; } public override string Name { diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs index 46c59a20e580c..65a17a23ad913 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs @@ -22,7 +22,6 @@ internal sealed class EENamedTypeSymbol : NamedTypeSymbol private readonly NamedTypeSymbol _baseType; private readonly string _name; private readonly ImmutableArray _typeParameters; - private readonly ImmutableArray _methods; internal EENamedTypeSymbol( NamespaceSymbol container, @@ -52,7 +51,7 @@ internal EENamedTypeSymbol( this.SourceTypeParameters = sourceTypeParameters; _typeParameters = getTypeParameters(currentFrame.ContainingType, this); VerifyTypeParameters(this, _typeParameters); - _methods = getMethods(currentFrame, this); + Methods = getMethods(currentFrame, this); } internal EENamedTypeSymbol( @@ -91,16 +90,13 @@ internal EENamedTypeSymbol( this.SubstitutedSourceType = typeMap.SubstituteNamedType(sourceType); TypeParameterChecker.Check(this.SubstitutedSourceType, _typeParameters); - _methods = getMethods(currentFrame, this); + Methods = getMethods(currentFrame, this); } protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) => throw ExceptionUtilities.Unreachable(); - internal ImmutableArray Methods - { - get { return _methods; } - } + internal ImmutableArray Methods { get; } internal override IEnumerable GetFieldsToEmit() { @@ -109,7 +105,7 @@ internal override IEnumerable GetFieldsToEmit() internal override IEnumerable GetMethodsToEmit() { - return _methods; + return Methods; } internal override ImmutableArray GetInterfacesToEmit() @@ -171,7 +167,7 @@ public override IEnumerable MemberNames public override ImmutableArray GetMembers() { - return _methods.Cast(); + return Methods.Cast(); } public override ImmutableArray GetMembers(string name) diff --git a/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpResultProvider.cs b/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpResultProvider.cs index 6c6b7a30ab919..71ab02273eaba 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpResultProvider.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpResultProvider.cs @@ -5,6 +5,8 @@ #nullable disable using System; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.ExpressionEvaluator; using Microsoft.VisualStudio.Debugger.ComponentInterfaces; using Type = Microsoft.VisualStudio.Debugger.Metadata.Type; @@ -38,5 +40,29 @@ internal override bool IsPrimitiveType(Type type) { return type.IsPredefinedType(); } + +#nullable enable + internal override bool TryGetGeneratedMemberDisplay(string metadataName, [NotNullWhen(true)] out string? displayName) + { + if (!GeneratedNameParser.TryParseGeneratedName(metadataName, out var kind, out var openBracketOffset, out var closeBracketOffset)) + { + displayName = null; + return false; + } + + switch (kind) + { + case GeneratedNameKind.PrimaryConstructorParameter: + // display the member using the unmangled name: + displayName = metadataName.Substring(openBracketOffset + 1, closeBracketOffset - openBracketOffset - 1); + return true; + + default: + // Do not display other generated members. + // Set the display name to metadata name for raw view. + displayName = null; + return false; + } + } } } diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs index df47eee9c8990..29bf1a279a554 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/CompileExpressionsTests.cs @@ -16,6 +16,7 @@ using Microsoft.VisualStudio.Debugger.Evaluation; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.UnitTests { @@ -506,7 +507,7 @@ async Task M(object x) // Test with CompileExpression rather than CompileExpressions // so field references in IL are named. // Debug build. - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, references: new[] { TestMetadata.Net40.SystemCore }); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, references: new[] { Net40.References.SystemCore }); WithRuntimeInstance( comp, references: null, @@ -541,7 +542,7 @@ .locals init (int V_0, }"); }); // Release build. - comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseDll, references: new[] { SystemCoreRef }); + comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseDll, references: new[] { SystemCoreRef }); { // Note from MoveNext() below that local CS$<>8__locals0 should not be // used in the compiled expression to access the display class since that diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs index 4265193e41e3c..704fe62aeb1f5 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs @@ -2345,7 +2345,7 @@ static void Main() } } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.UnsafeDebugDll); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "C.Main"); @@ -2380,7 +2380,7 @@ static void Main() } } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.UnsafeDebugDll); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "C.Main"); @@ -4902,7 +4902,7 @@ static void Main() { } }"; - var compilation0 = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); WithRuntimeInstance(compilation0, runtime => { var context = CreateMethodContext(runtime, "C.Main"); @@ -5919,7 +5919,7 @@ public void M() } } "; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "C.<>c__0.b__0_0"); @@ -5952,7 +5952,7 @@ public void M() { } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); WithRuntimeInstance(compilation, runtime => { var context = CreateMethodContext(runtime, "C.M"); @@ -6154,7 +6154,7 @@ static void M() { } }"; - var compilation0 = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); WithRuntimeInstance(compilation0, runtime => { var context = CreateMethodContext(runtime, methodName: "C.M"); @@ -6193,7 +6193,7 @@ void M(Func f) M(() => x); } }"; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "C.M"); @@ -6416,7 +6416,7 @@ static void M() } } }"; - var compilation0 = CreateCompilationWithMscorlib45( + var compilation0 = CreateCompilationWithMscorlib461( source, options: TestOptions.DebugDll, references: new[] { SystemCoreRef }); diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/HoistedStateMachineLocalTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/HoistedStateMachineLocalTests.cs index 9ca94da5e118e..dea8f37c45f2b 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/HoistedStateMachineLocalTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/HoistedStateMachineLocalTests.cs @@ -215,7 +215,7 @@ .locals init (int V_0, }} "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { EvaluationContext context; @@ -264,7 +264,7 @@ .locals init (int V_0, public void AsyncLambda_Instance_CaptureNothing() { var source = string.Format(asyncLambdaSourceTemplate, "/*instance*/", "1"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c.<b__1_0>d.MoveNext"); @@ -304,7 +304,7 @@ .locals init (int V_0, public void AsyncLambda_Instance_CaptureLocal() { var source = string.Format(asyncLambdaSourceTemplate, "/*instance*/", "x"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__DisplayClass1_0.<b__0>d.MoveNext"); @@ -358,7 +358,7 @@ .locals init (int V_0, public void AsyncLambda_Instance_CaptureParameter() { var source = string.Format(asyncLambdaSourceTemplate, "/*instance*/", "u.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__DisplayClass1_0.<b__0>d.MoveNext"); @@ -412,7 +412,7 @@ .locals init (int V_0, public void AsyncLambda_Instance_CaptureLambdaParameter() { var source = string.Format(asyncLambdaSourceTemplate, "/*instance*/", "ch.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c.<b__1_0>d.MoveNext"); @@ -452,7 +452,7 @@ .locals init (int V_0, public void AsyncLambda_Instance_CaptureThis() { var source = string.Format(asyncLambdaSourceTemplate, "/*instance*/", "t.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<b__1_0>d.MoveNext"); @@ -506,7 +506,7 @@ .locals init (int V_0, public void AsyncLambda_Instance_CaptureThisAndLocal() { var source = string.Format(asyncLambdaSourceTemplate, "/*instance*/", "x + t.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__DisplayClass1_0.<b__0>d.MoveNext"); @@ -575,7 +575,7 @@ .locals init (int V_0, public void AsyncLambda_Static_CaptureNothing() { var source = string.Format(asyncLambdaSourceTemplate, "static", "1"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c.<b__1_0>d.MoveNext"); @@ -615,7 +615,7 @@ .locals init (int V_0, public void AsyncLambda_Static_CaptureLocal() { var source = string.Format(asyncLambdaSourceTemplate, "static", "x"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__DisplayClass1_0.<b__0>d.MoveNext"); @@ -669,7 +669,7 @@ .locals init (int V_0, public void AsyncLambda_Static_CaptureParameter() { var source = string.Format(asyncLambdaSourceTemplate, "static", "u.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__DisplayClass1_0.<b__0>d.MoveNext"); @@ -723,7 +723,7 @@ .locals init (int V_0, public void AsyncLambda_Static_CaptureLambdaParameter() { var source = string.Format(asyncLambdaSourceTemplate, "static", "ch.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c.<b__1_0>d.MoveNext"); @@ -763,7 +763,7 @@ .locals init (int V_0, public void GenericAsyncLambda_Instance_CaptureNothing() { var source = string.Format(genericAsyncLambdaSourceTemplate, "/*instance*/", "1"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__1.<b__1_0>d.MoveNext"); @@ -809,7 +809,7 @@ .locals init (int V_0, public void GenericAsyncLambda_Instance_CaptureLocal() { var source = string.Format(genericAsyncLambdaSourceTemplate, "/*instance*/", "x"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__DisplayClass1_0.<b__0>d.MoveNext"); @@ -869,7 +869,7 @@ .locals init (int V_0, public void GenericAsyncLambda_Instance_CaptureParameter() { var source = string.Format(genericAsyncLambdaSourceTemplate, "/*instance*/", "u.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__DisplayClass1_0.<b__0>d.MoveNext"); @@ -929,7 +929,7 @@ .locals init (int V_0, public void GenericAsyncLambda_Instance_CaptureLambdaParameter() { var source = string.Format(genericAsyncLambdaSourceTemplate, "/*instance*/", "ch.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__1.<b__1_0>d.MoveNext"); @@ -975,7 +975,7 @@ .locals init (int V_0, public void GenericAsyncLambda_Instance_CaptureThis() { var source = string.Format(genericAsyncLambdaSourceTemplate, "/*instance*/", "t.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<b__1_0>d.MoveNext"); @@ -1035,7 +1035,7 @@ .locals init (int V_0, public void GenericAsyncLambda_Instance_CaptureThisAndLocal() { var source = string.Format(genericAsyncLambdaSourceTemplate, "/*instance*/", "x + t.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__DisplayClass1_0.<b__0>d.MoveNext"); @@ -1110,7 +1110,7 @@ .locals init (int V_0, public void GenericAsyncLambda_Static_CaptureNothing() { var source = string.Format(genericAsyncLambdaSourceTemplate, "static", "1"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__1.<b__1_0>d.MoveNext"); @@ -1156,7 +1156,7 @@ .locals init (int V_0, public void GenericAsyncLambda_Static_CaptureLocal() { var source = string.Format(genericAsyncLambdaSourceTemplate, "static", "x"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__DisplayClass1_0.<b__0>d.MoveNext"); @@ -1216,7 +1216,7 @@ .locals init (int V_0, public void GenericAsyncLambda_Static_CaptureParameter() { var source = string.Format(genericAsyncLambdaSourceTemplate, "static", "u.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__DisplayClass1_0.<b__0>d.MoveNext"); @@ -1276,7 +1276,7 @@ .locals init (int V_0, public void GenericAsyncLambda_Static_CaptureLambdaParameter() { var source = string.Format(genericAsyncLambdaSourceTemplate, "static", "ch.GetHashCode()"); - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: GetUniqueName()); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "D.<>c__1.<b__1_0>d.MoveNext"); @@ -1390,9 +1390,12 @@ static IEnumerable M() private static string[] GetLocalNames(EvaluationContext context) { string unused; - var locals = new ArrayBuilder(); + var locals = ArrayBuilder.GetInstance(); context.CompileGetLocals(locals, argumentsOnly: false, typeName: out unused, testData: null); - return locals.Select(l => l.LocalName).ToArray(); + var result = locals.Select(l => l.LocalName).ToArray(); + + locals.Free(); + return result; } } } diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/HoistedThisTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/HoistedThisTests.cs index f3181e47eaafb..1cec6a2fd690e 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/HoistedThisTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/HoistedThisTests.cs @@ -932,7 +932,7 @@ static event Action E private void VerifyHasThis(string source, string methodName, string expectedType, string expectedIL, bool thisCanBeElided = true) { - var sourceCompilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: ExpressionCompilerUtilities.GenerateUniqueName()); + var sourceCompilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: ExpressionCompilerUtilities.GenerateUniqueName()); WithRuntimeInstance(sourceCompilation, runtime => { var context = CreateMethodContext(runtime, methodName); @@ -998,7 +998,7 @@ private static void VerifyMethodData(CompilationTestData.MethodData methodData, private void VerifyNoThis(string source, string methodName) { - var comp = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugDll); WithRuntimeInstance(comp, runtime => VerifyNoThis(CreateMethodContext(runtime, methodName))); } @@ -1077,7 +1077,7 @@ async Task F() await Console.Out.WriteLineAsync(this.ToString()); } }"; - var compilation0 = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); WithRuntimeInstance(compilation0, runtime => { var context = CreateMethodContext(runtime, "C.d__1.MoveNext"); @@ -1190,7 +1190,7 @@ async Task M() await Console.Out.WriteLineAsync(this.ToString()); } }"; - var compilation0 = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); WithRuntimeInstance(compilation0, runtime => { var context = CreateMethodContext(runtime, "Derived.d__1.MoveNext"); diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs index 32a22b5680ce8..ab55a95a123f1 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/InstructionDecoderTests.cs @@ -442,7 +442,7 @@ private string GetReturnTypeName(string source, string methodName, Type[] typeAr private MethodSymbol GetConstructedMethod(string source, string methodName, string[] serializedTypeArgumentNames, CSharpInstructionDecoder instructionDecoder) { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, assemblyName: nameof(InstructionDecoderTests)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, assemblyName: nameof(InstructionDecoderTests)); var runtime = CreateRuntimeInstance(compilation); var moduleInstances = runtime.Modules; var blocks = moduleInstances.SelectAsArray(m => m.MetadataBlock); diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalFunctionTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalFunctionTests.cs index 604dede5084af..e81aed85b3051 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalFunctionTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalFunctionTests.cs @@ -395,7 +395,7 @@ static void Main() } } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.UnsafeDebugDll); WithRuntimeInstance(comp, runtime => { var context = CreateMethodContext(runtime, "C.Main"); diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalsTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalsTests.cs index 6648928c9825f..288b380a00f08 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalsTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalsTests.cs @@ -532,7 +532,7 @@ async Task M(object o) } } }"; - var compilation0 = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, + var compilation0 = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, references: new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }); WithRuntimeInstance(compilation0, runtime => { @@ -2101,7 +2101,7 @@ internal async Task F(U y) where U : class return this.x ?? (object)y ?? z; } }"; - var compilation0 = CreateCompilationWithMscorlib45( + var compilation0 = CreateCompilationWithMscorlib461( source, options: TestOptions.DebugDll, references: new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }); @@ -2172,7 +2172,7 @@ static async Task M(object x) await F(y); } }"; - var compilation0 = CreateCompilationWithMscorlib45( + var compilation0 = CreateCompilationWithMscorlib461( source, options: TestOptions.DebugDll, references: new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }); @@ -2242,7 +2242,7 @@ static async Task M(object x) } } }"; - var compilation0 = CreateCompilationWithMscorlib45( + var compilation0 = CreateCompilationWithMscorlib461( source, options: TestOptions.DebugDll, references: new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }); @@ -2356,7 +2356,7 @@ async static Task M(int x) return x; } }"; - var compilation0 = CreateCompilationWithMscorlib45( + var compilation0 = CreateCompilationWithMscorlib461( source, options: TestOptions.DebugDll, references: new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }); @@ -2417,7 +2417,7 @@ static void M() }; } }"; - var compilation0 = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); WithRuntimeInstance(compilation0, runtime => { var context = CreateMethodContext(runtime, methodName: "C.<>c.<b__0_0>d.MoveNext"); @@ -2964,7 +2964,7 @@ static async Task M2(int x) return local; } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); WithRuntimeInstance(compilation, runtime => { string displayClassName; @@ -3237,7 +3237,7 @@ static async Task M4() return x; } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); WithRuntimeInstance(compilation, runtime => { string displayClassName; @@ -3339,7 +3339,7 @@ static async Task M() } } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); WithRuntimeInstance(compilation, runtime => { var context = CreateMethodContext(runtime, "C.d__1.MoveNext", atLineNumber: 999); @@ -3398,7 +3398,7 @@ static IEnumerable M() yield return o; } }"; - var compilation0 = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); WithRuntimeInstance(compilation0, runtime => { var context = CreateMethodContext(runtime, "C.d__1.MoveNext", atLineNumber: 999); @@ -3495,7 +3495,7 @@ async void M() await F(() => G(s)); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); WithRuntimeInstance(compilation, runtime => { var context = CreateMethodContext(runtime, "C.d__2.MoveNext()"); @@ -3547,7 +3547,7 @@ async void M() #line 999 } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); WithRuntimeInstance(compilation, runtime => { var context = CreateMethodContext(runtime, "C.d__0.MoveNext()", atLineNumber: 999); @@ -3857,13 +3857,13 @@ static void DummySequencePoint() { } }"; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseDll); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseDll); WithRuntimeInstance(comp, runtime => { EvaluationContext context; context = CreateMethodContext(runtime, "C.d__0.MoveNext", atLineNumber: 500); string unused; - var locals = new ArrayBuilder(); + var locals = ArrayBuilder.GetInstance(); context.CompileGetLocals(locals, argumentsOnly: true, typeName: out unused, testData: null); var names = locals.Select(l => l.LocalName).ToArray(); // The order must confirm the order of the arguments in the method signature. @@ -3877,7 +3877,7 @@ static void DummySequencePoint() EvaluationContext context; context = CreateMethodContext(runtime, "C.d__0.MoveNext", atLineNumber: 500); string unused; - var locals = new ArrayBuilder(); + var locals = ArrayBuilder.GetInstance(); context.CompileGetLocals(locals, argumentsOnly: true, typeName: out unused, testData: null); var names = locals.Select(l => l.LocalName).ToArray(); // The problem is not fixed in versions before 4.5: the order of arguments can be wrong. @@ -3906,14 +3906,14 @@ static void DummySequencePoint() { } }"; - var references = TargetFrameworkUtil.Mscorlib461ExtendedReferences.Concat(new[] { Net461.References.SystemThreadingTasks, TestMetadata.SystemThreadingTasksExtensions.PortableLib }); + MetadataReference[] references = [.. TargetFrameworkUtil.Mscorlib461ExtendedReferences, Net461.ExtraReferences.SystemThreadingTasksExtensions]; var comp = CreateEmptyCompilation(new[] { source, AsyncStreamsTypes }, references: references); WithRuntimeInstance(comp, references, runtime => { EvaluationContext context; context = CreateMethodContext(runtime, "C.d__0.MoveNext", atLineNumber: 500); string unused; - var locals = new ArrayBuilder(); + var locals = ArrayBuilder.GetInstance(); context.CompileGetLocals(locals, argumentsOnly: true, typeName: out unused, testData: null); var names = locals.Select(l => l.LocalName).ToArray(); // The order must confirm the order of the arguments in the method signature. diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/MissingAssemblyTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/MissingAssemblyTests.cs index 439c9a71faea2..1b0cce7b9beb0 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/MissingAssemblyTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/MissingAssemblyTests.cs @@ -21,6 +21,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.UnitTests { @@ -739,7 +740,7 @@ class UseLinq var context = CreateMethodContext(runtime, "C.M"); var systemCore = SystemCoreRef.ToModuleInstance(); - var fakeSystemLinq = CreateCompilationWithMscorlib45("", assemblyName: "System.Linq"). + var fakeSystemLinq = CreateCompilationWithMscorlib461("", assemblyName: "System.Linq"). EmitToImageReference().ToModuleInstance(); string errorMessage; @@ -894,11 +895,11 @@ .locals init (int V_0, //x private static void TupleContextNoSystemRuntime(string source, string methodName, string expression, string expectedIL, LanguageVersion languageVersion = LanguageVersion.CSharp7) { - var comp = CreateCompilationWithMscorlib40(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), - references: new[] { SystemRuntimeFacadeRef, ValueTupleRef }, options: TestOptions.DebugDll); + var comp = CreateEmptyCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + references: [Net461.References.mscorlib, Net461.References.SystemRuntime, ValueTupleLegacyRef], options: TestOptions.DebugDll); using (var systemRuntime = SystemRuntimeFacadeRef.ToModuleInstance()) { - WithRuntimeInstance(comp, new[] { MscorlibRef, ValueTupleRef }, runtime => + WithRuntimeInstance(comp, [Net461.References.mscorlib, ValueTupleLegacyRef], runtime => { ImmutableArray blocks; Guid moduleVersionId; diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/TupleTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/TupleTests.cs index 60da715ed7e0f..9398a0d79b427 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/TupleTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/TupleTests.cs @@ -434,8 +434,8 @@ static void M() { } }"; - var comp = CreateCompilationWithMscorlib40(source, new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugDll); - WithRuntimeInstance(comp, new[] { ValueTupleRef, SystemRuntimeFacadeRef, MscorlibRef }, runtime => + var comp = CreateCompilationWithMscorlib40(source, new[] { ValueTupleLegacyRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugDll); + WithRuntimeInstance(comp, new[] { ValueTupleLegacyRef, SystemRuntimeFacadeRef, MscorlibRef }, runtime => { var context = CreateMethodContext( runtime, @@ -499,8 +499,8 @@ static void M() { } }"; - var comp = CreateCompilationWithMscorlib40(source, new[] { SystemRuntimeFacadeRef, ValueTupleRef }, options: TestOptions.DebugDll); - WithRuntimeInstance(comp, new[] { MscorlibRef, SystemCoreRef, SystemRuntimeFacadeRef, ValueTupleRef }, runtime => + var comp = CreateCompilationWithMscorlib40(source, new[] { SystemRuntimeFacadeRef, ValueTupleLegacyRef }, options: TestOptions.DebugDll); + WithRuntimeInstance(comp, new[] { MscorlibRef, SystemCoreRef, SystemRuntimeFacadeRef, ValueTupleLegacyRef }, runtime => { var context = CreateMethodContext(runtime, "C.M"); var alias = new Alias( diff --git a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/CSharpResultProviderTestBase.cs b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/CSharpResultProviderTestBase.cs index a7a748440564e..04c0a3bc59a41 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/CSharpResultProviderTestBase.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/CSharpResultProviderTestBase.cs @@ -45,13 +45,13 @@ private static DkmInspectionSession CreateDkmInspectionSession(CSharpFormatter f public static Assembly GetAssembly(string source) { - var comp = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source); + var comp = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source); return ReflectionUtilities.Load(comp.EmitToArray()); } public static Assembly GetUnsafeAssembly(string source) { - var comp = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, options: TestOptions.UnsafeReleaseDll); + var comp = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.UnsafeReleaseDll); return ReflectionUtilities.Load(comp.EmitToArray()); } diff --git a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/FullNameTests.cs b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/FullNameTests.cs index 57fbc515f79a8..a15ce76b7ccd0 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/FullNameTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/FullNameTests.cs @@ -1001,7 +1001,7 @@ .field public object 'P' IDkmClrFullNameProvider2 fullNameProvider = new CSharpFormatter(); var inspectionContext = CreateDkmInspectionContext(); - Assert.Equal("P", fullNameProvider.GetClrNameForField(inspectionContext, new DkmClrRuntimeInstance(assembly).Modules[0], fieldToken)); + Assert.Equal("StringParameter", fullNameProvider.GetClrNameForField(inspectionContext, new DkmClrRuntimeInstance(assembly).Modules[0], fieldToken)); } } } diff --git a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/ResultsViewTests.cs b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/ResultsViewTests.cs index 99843438b4009..c633066267e3d 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/ResultsViewTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/ResultsViewTests.cs @@ -1851,5 +1851,32 @@ private DkmEvaluationResult FormatPropertyValue(DkmClrRuntimeInstance runtime, o CreateDkmClrValue(propertyValue, type: valueType, valueFlags: DkmClrValueFlags.Synthetic), declaredType: propertyType); } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/74082")] + public void LiftedPrimaryConstructorParameters() + { + var source = """ + class C(int x, int y) { int F() => x; int A = y; int Z => 2; } + """; + var assembly = GetAssembly(source); + var assemblies = ReflectionUtilities.GetMscorlibAndSystemCore(assembly); + using (ReflectionUtilities.LoadAssemblies(assemblies)) + { + var runtime = new DkmClrRuntimeInstance(assemblies); + var type = assembly.GetType("C"); + var value = CreateDkmClrValue( + value: type.Instantiate([3, 1]), + type: runtime.GetType((TypeImpl)type)); + var evalResult = FormatResult("o", value); + Verify(evalResult, + EvalResult("o", "{C}", "C", "o", DkmEvaluationResultFlags.Expandable)); + var children = GetChildren(evalResult); + Verify(children, + EvalResult(name: "A", value: "1", type: "int", fullName: "o.A", DkmEvaluationResultFlags.CanFavorite), + EvalResult(name: "Z", value: "2", type: "int", fullName: "o.Z", DkmEvaluationResultFlags.CanFavorite | DkmEvaluationResultFlags.ReadOnly), + EvalResult(name: "x", value: "3", type: "int", fullName: null, DkmEvaluationResultFlags.CanFavorite)); + } + } } } diff --git a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/TupleTests.cs b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/TupleTests.cs index 05a04577448f4..adb67771ee299 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/TupleTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/TupleTests.cs @@ -355,7 +355,7 @@ public void Dynamic() }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1))); using (runtime.Load()) @@ -391,7 +391,7 @@ public void Names_LongTuple() }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1))); using (runtime.Load()) @@ -423,7 +423,7 @@ public void PartialNames() }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1))); using (runtime.Load()) @@ -475,7 +475,7 @@ class C }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1))); using (runtime.Load()) @@ -504,7 +504,7 @@ public void NamesAndDynamic() }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1))); using (runtime.Load()) @@ -550,7 +550,7 @@ class C }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1))); using (runtime.Load()) @@ -590,7 +590,7 @@ class C }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1))); using (runtime.Load()) @@ -658,7 +658,7 @@ class B }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1))); using (runtime.Load()) @@ -749,7 +749,7 @@ class C }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1))); using (runtime.Load()) @@ -824,7 +824,7 @@ object Nine }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1))); using (runtime.Load()) @@ -1156,7 +1156,7 @@ public void Exception() }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); DkmClrRuntimeInstance runtime = null; runtime = new DkmClrRuntimeInstance( @@ -1199,7 +1199,7 @@ class E : System.Exception }"; var assembly0 = GenerateTupleAssembly(); var reference0 = AssemblyMetadata.CreateFromImage(assembly0).GetReference(); - var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib45AndCSharp(source, references: new[] { reference0 }); + var compilation1 = CSharpTestBase.CreateCompilationWithMscorlib461AndCSharp(source, references: new[] { reference0 }); var assembly1 = compilation1.EmitToArray(); var runtime = new DkmClrRuntimeInstance(ReflectionUtilities.GetMscorlib(ReflectionUtilities.Load(assembly0), ReflectionUtilities.Load(assembly1))); using (runtime.Load()) diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/MemberExpansion.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/MemberExpansion.cs index b6575c80b81e4..11db75b2729a3 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/MemberExpansion.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Expansion/MemberExpansion.cs @@ -13,6 +13,7 @@ using Microsoft.VisualStudio.Debugger.Evaluation; using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation; using Microsoft.VisualStudio.Debugger.Metadata; +using Type = Microsoft.VisualStudio.Debugger.Metadata.Type; namespace Microsoft.CodeAnalysis.ExpressionEvaluator { @@ -75,9 +76,9 @@ internal static Expansion CreateExpansion( var allMembers = ArrayBuilder.GetInstance(); var includeInherited = (flags & ExpansionFlags.IncludeBaseMembers) == ExpansionFlags.IncludeBaseMembers; var hideNonPublic = (inspectionContext.EvaluationFlags & DkmEvaluationFlags.HideNonPublicMembers) == DkmEvaluationFlags.HideNonPublicMembers; - var includeCompilerGenerated = (inspectionContext.EvaluationFlags & DkmEvaluationFlags.ShowValueRaw) == DkmEvaluationFlags.ShowValueRaw; + var raw = (inspectionContext.EvaluationFlags & DkmEvaluationFlags.ShowValueRaw) == DkmEvaluationFlags.ShowValueRaw; var favoritesInfo = supportsFavorites ? type.GetFavorites() : null; - runtimeType.AppendTypeMembers(allMembers, predicate, declaredTypeAndInfo.Type, appDomain, includeInherited, hideNonPublic, isProxyType, includeCompilerGenerated, supportsFavorites, favoritesInfo); + runtimeType.AppendTypeMembers(allMembers, predicate, resultProvider, declaredTypeAndInfo.Type, appDomain, includeInherited, hideNonPublic, isProxyType, raw, supportsFavorites, favoritesInfo); var favoritesMembersByName = new Dictionary(); @@ -86,7 +87,7 @@ internal static Expansion CreateExpansion( // Favorites are currently never static if (member.IsFavorite && !value.IsNull) { - favoritesMembersByName.Add(member.Name, member); + favoritesMembersByName.Add(member.DisplayName, member); } else if (member.IsStatic) { @@ -460,7 +461,7 @@ private static EvalResult GetRow( inspectionContext: inspectionContext); } } - +#nullable enable internal static EvalResult CreateMemberDataItem( ResultProvider resultProvider, DkmInspectionContext inspectionContext, @@ -474,35 +475,50 @@ internal static EvalResult CreateMemberDataItem( var fullNameProvider = resultProvider.FullNameProvider; var declaredType = member.Type; var declaredTypeInfo = customTypeInfoMap.SubstituteCustomTypeInfo(member.OriginalDefinitionType, member.TypeInfo); - string memberName; + string? memberNameForFullName; + // Considering, we're not handling the case of a member inherited from a generic base type. - var typeDeclaringMember = member.GetExplicitlyImplementedInterface(out memberName) ?? member.DeclaringType; - var typeDeclaringMemberInfo = typeDeclaringMember.IsInterface - ? customTypeInfoMap.SubstituteCustomTypeInfo(typeDeclaringMember.GetInterfaceListEntry(member.DeclaringType), customInfo: null) + if (member.TryGetExplicitlyImplementedInterface(out var declaringType, out var memberDisplayName)) + { + // full name will include cast to the interface, e.g. "((I)obj).MemberName": + memberNameForFullName = memberDisplayName; + } + else + { + declaringType = member.DeclaringType; + memberDisplayName = member.DisplayName; + memberNameForFullName = member.MetadataName; + } + + var declaringTypeInfo = declaringType.IsInterface + ? customTypeInfoMap.SubstituteCustomTypeInfo(declaringType.GetInterfaceListEntry(member.DeclaringType), customInfo: null) : null; - var memberNameForFullName = fullNameProvider.GetClrValidIdentifier(inspectionContext, memberName); + var appDomain = memberValue.Type.AppDomain; - string fullName; + string? fullName; + + memberNameForFullName = fullNameProvider.GetClrValidIdentifier(inspectionContext, memberNameForFullName); if (memberNameForFullName == null) { fullName = null; } else { - memberName = memberNameForFullName; + memberDisplayName = memberNameForFullName; fullName = MakeFullName( fullNameProvider, inspectionContext, memberNameForFullName, - new TypeAndCustomInfo(DkmClrType.Create(appDomain, typeDeclaringMember), typeDeclaringMemberInfo), // Note: Won't include DynamicAttribute. + new TypeAndCustomInfo(DkmClrType.Create(appDomain, declaringType), declaringTypeInfo), // Note: Won't include DynamicAttribute. member.RequiresExplicitCast, member.IsStatic, parent); } + return resultProvider.CreateDataItem( inspectionContext, - memberName, - typeDeclaringMemberAndInfo: (member.IncludeTypeInMemberName || typeDeclaringMember.IsInterface) ? new TypeAndCustomInfo(DkmClrType.Create(appDomain, typeDeclaringMember), typeDeclaringMemberInfo) : default(TypeAndCustomInfo), // Note: Won't include DynamicAttribute. + memberDisplayName, + typeDeclaringMemberAndInfo: (member.IncludeTypeInMemberName || declaringType.IsInterface) ? new TypeAndCustomInfo(DkmClrType.Create(appDomain, declaringType), declaringTypeInfo) : default(TypeAndCustomInfo), // Note: Won't include DynamicAttribute. declaredTypeAndInfo: new TypeAndCustomInfo(DkmClrType.Create(appDomain, declaredType), declaredTypeInfo), value: memberValue, useDebuggerDisplay: parent != null, @@ -517,7 +533,7 @@ internal static EvalResult CreateMemberDataItem( isFavorite: member.IsFavorite, supportsFavorites: supportsFavorites); } - +#nullable disable private static string MakeFullName( IDkmClrFullNameProvider fullNameProvider, DkmInspectionContext inspectionContext, diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/CustomTypeInfoTypeArgumentMap.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/CustomTypeInfoTypeArgumentMap.cs index d7577931736af..cc1d7ddc53345 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/CustomTypeInfoTypeArgumentMap.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/CustomTypeInfoTypeArgumentMap.cs @@ -19,7 +19,6 @@ internal sealed class CustomTypeInfoTypeArgumentMap private readonly Type _typeDefinition; private readonly ReadOnlyCollection _dynamicFlags; private readonly int[] _dynamicFlagStartIndices; - private readonly ReadOnlyCollection _tupleElementNames; private readonly int[] _tupleElementNameStartIndices; private CustomTypeInfoTypeArgumentMap() @@ -47,7 +46,7 @@ private CustomTypeInfoTypeArgumentMap( _typeDefinition = typeDefinition; _dynamicFlags = dynamicFlags; _dynamicFlagStartIndices = dynamicFlagStartIndices; - _tupleElementNames = tupleElementNames; + TupleElementNames = tupleElementNames; _tupleElementNameStartIndices = tupleElementNameStartIndices; } @@ -88,7 +87,7 @@ internal static CustomTypeInfoTypeArgumentMap Create(TypeAndCustomInfo typeAndIn tupleElementNameStartIndices); } - internal ReadOnlyCollection TupleElementNames => _tupleElementNames; + internal ReadOnlyCollection TupleElementNames { get; } internal DkmClrCustomTypeInfo SubstituteCustomTypeInfo(Type type, DkmClrCustomTypeInfo customInfo) { @@ -153,7 +152,7 @@ private ReadOnlyCollection SubstituteTupleElementNames(Type type, ReadOn { AppendRangeFor( curr, - _tupleElementNames, + TupleElementNames, _tupleElementNameStartIndices, CustomTypeInfo.GetTupleElementNameIfAny, builder); diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/MemberAndDeclarationInfo.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/MemberAndDeclarationInfo.cs index 1b01698cd6577..e253fc1af9e86 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/MemberAndDeclarationInfo.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/MemberAndDeclarationInfo.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation; using Microsoft.VisualStudio.Debugger.Metadata; using Roslyn.Utilities; @@ -59,10 +60,10 @@ internal readonly struct MemberAndDeclarationInfo private readonly MemberInfo _member; + public readonly string DisplayName; public readonly DkmClrDebuggerBrowsableAttributeState? BrowsableState; - public readonly bool HideNonPublic; - public readonly bool IncludeTypeInMemberName; - public readonly bool RequiresExplicitCast; + public readonly bool IsGenerated; + public readonly bool CanFavorite; public readonly bool IsFavorite; @@ -71,21 +72,27 @@ internal readonly struct MemberAndDeclarationInfo /// private readonly int _inheritanceLevel; - public MemberAndDeclarationInfo(MemberInfo member, DkmClrDebuggerBrowsableAttributeState? browsableState, DeclarationInfo info, int inheritanceLevel, bool canFavorite, bool isFavorite) + private readonly DeclarationInfo _info; + + public MemberAndDeclarationInfo(MemberInfo member, string displayName, DkmClrDebuggerBrowsableAttributeState? browsableState, DeclarationInfo info, int inheritanceLevel, bool isGenerated, bool canFavorite, bool isFavorite) { Debug.Assert(member != null); _member = member; - this.BrowsableState = browsableState; - this.HideNonPublic = info.IsSet(DeclarationInfo.HideNonPublic); - this.IncludeTypeInMemberName = info.IsSet(DeclarationInfo.IncludeTypeInMemberName); - this.RequiresExplicitCast = info.IsSet(DeclarationInfo.RequiresExplicitCast); - this.CanFavorite = canFavorite && SupportsCanFavorite(member, info); - this.IsFavorite = isFavorite; - + _info = info; _inheritanceLevel = inheritanceLevel; + + DisplayName = displayName; + BrowsableState = browsableState; + CanFavorite = canFavorite && SupportsCanFavorite(member, info); + IsFavorite = isFavorite; + IsGenerated = isGenerated; } + public bool HideNonPublic => _info.IsSet(DeclarationInfo.HideNonPublic); + public bool IncludeTypeInMemberName => _info.IsSet(DeclarationInfo.IncludeTypeInMemberName); + public bool RequiresExplicitCast => _info.IsSet(DeclarationInfo.RequiresExplicitCast); + public Type DeclaringType { get @@ -118,7 +125,7 @@ public MemberTypes MemberType } } - public string Name + public string MetadataName { get { @@ -211,10 +218,9 @@ public DkmClrCustomTypeInfo TypeInfo } } - public Type GetExplicitlyImplementedInterface(out string memberName) +#nullable enable + public bool TryGetExplicitlyImplementedInterface([NotNullWhen(true)] out Type? interfaceType, [NotNullWhen(true)] out string? memberDisplayName) { - memberName = _member.Name; - // We only display fields and properties and fields never implement interface members. if (_member.MemberType == MemberTypes.Property) { @@ -222,7 +228,7 @@ public Type GetExplicitlyImplementedInterface(out string memberName) // implements an interface member, but it does characterize the set of members we're // interested in displaying differently. For example, if the property is from VB, it will // be an explicit interface implementation, but will not have a dot. - var dotPos = memberName.LastIndexOf('.'); + var dotPos = _member.Name.LastIndexOf('.'); if (dotPos >= 0) { var property = (PropertyInfo)_member; @@ -235,21 +241,25 @@ public Type GetExplicitlyImplementedInterface(out string memberName) { foreach (var interfaceAccessor in accessor.GetExplicitInterfacesImplemented()) { - memberName = memberName.Substring(dotPos + 1); - return interfaceAccessor.DeclaringType; + memberDisplayName = _member.Name.Substring(dotPos + 1); + interfaceType = interfaceAccessor.DeclaringType; + RoslynDebug.AssertNotNull(interfaceType); + return true; } } } } - return null; + interfaceType = null; + memberDisplayName = null; + return false; } private sealed class MemberNameComparer : IComparer { public int Compare(MemberAndDeclarationInfo x, MemberAndDeclarationInfo y) { - var comp = string.Compare(x.Name, y.Name, StringComparison.Ordinal); + var comp = string.Compare(x.DisplayName, y.DisplayName, StringComparison.Ordinal); return comp != 0 ? comp : (y._inheritanceLevel - x._inheritanceLevel); } } diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs index f78a77ac28306..816fc0f5ecb3d 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/TypeHelpers.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using Microsoft.VisualStudio.Debugger.Clr; using Microsoft.VisualStudio.Debugger.Evaluation; using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation; @@ -30,12 +31,13 @@ internal static void AppendTypeMembers( this Type type, ArrayBuilder includedMembers, Predicate predicate, + ResultProvider resultProvider, Type declaredType, DkmClrAppDomain appDomain, bool includeInherited, bool hideNonPublic, bool isProxyType, - bool includeCompilerGenerated, + bool raw, bool supportsFavorites, DkmClrObjectFavoritesInfo favoritesInfo) { @@ -99,9 +101,20 @@ internal static void AppendTypeMembers( foreach (var member in type.GetMembers(MemberBindingFlags)) { var memberName = member.Name; - if (!includeCompilerGenerated && memberName.IsCompilerGenerated()) + var isGenerated = memberName.IsCompilerGenerated(); + + if (isGenerated) { - continue; + // Some generated names are displayed under their original (unmangled) name, + // others are only shown when displaying raw object. + if (resultProvider.TryGetGeneratedMemberDisplay(memberName, out var unmangledMemberName)) + { + memberName = unmangledMemberName; + } + else if (!raw) + { + continue; + } } // The native EE shows proxy members regardless of accessibility if they have a @@ -172,9 +185,11 @@ internal static void AppendTypeMembers( includedMembers.Add( new MemberAndDeclarationInfo( member, + memberName, browsableStateValue, previousDeclaration, inheritanceLevel, + isGenerated: isGenerated, canFavorite: supportsFavorites && !previousDeclaration.HasFlag(DeclarationInfo.IncludeTypeInMemberName), isFavorite: favoritesMemberNames?.ContainsKey(memberName) == true && !previousDeclaration.HasFlag(DeclarationInfo.IncludeTypeInMemberName))); } @@ -876,9 +891,8 @@ internal static Type GetInterfaceListEntry(this Type interfaceType, Type declara internal static MemberAndDeclarationInfo GetMemberByName(this DkmClrType type, string name) { - var members = type.GetLmrType().GetMember(name, TypeHelpers.MemberBindingFlags); - Debug.Assert(members.Length == 1); - return new MemberAndDeclarationInfo(members[0], browsableState: null, info: DeclarationInfo.None, inheritanceLevel: 0, canFavorite: false, isFavorite: false); + var member = type.GetLmrType().GetMember(name, MemberBindingFlags).Single(); + return new MemberAndDeclarationInfo(member, displayName: member.Name, browsableState: null, info: DeclarationInfo.None, inheritanceLevel: 0, isGenerated: false, canFavorite: false, isFavorite: false); } } } diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/ValueHelpers.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/ValueHelpers.cs index 83cf812b482db..b46c0b1fb962e 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/ValueHelpers.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Helpers/ValueHelpers.cs @@ -42,7 +42,7 @@ internal static string GetExceptionMessage(this DkmClrValue value, DkmInspection internal static DkmClrValue GetMemberValue(this DkmClrValue value, MemberAndDeclarationInfo member, DkmInspectionContext inspectionContext) { // Note: GetMemberValue() may return special value when func-eval of properties is disabled. - return value.GetMemberValue(member.Name, (int)member.MemberType, member.DeclaringType.FullName, inspectionContext); + return value.GetMemberValue(member.MetadataName, (int)member.MemberType, member.DeclaringType.FullName, inspectionContext); } internal static string Parenthesize(this string expr) diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs index aa6e9f57507e4..846b5e97b5a00 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/ResultProvider.cs @@ -9,6 +9,7 @@ using System; using System.Collections.ObjectModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.VisualStudio.Debugger; using Microsoft.VisualStudio.Debugger.CallStack; @@ -61,6 +62,14 @@ internal ResultProvider(IDkmClrFormatter2 formatter2, IDkmClrFullNameProvider fu internal abstract bool IsPrimitiveType(Type type); +#nullable enable + /// + /// Returns true if a generated member of should be displayed. + /// is set to the unmangled name to be displayed. + /// + internal abstract bool TryGetGeneratedMemberDisplay(string metadataName, [NotNullWhen(true)] out string? displayName); +#nullable disable + void IDkmClrResultProvider.GetResult(DkmClrValue value, DkmWorkList workList, DkmClrType declaredType, DkmClrCustomTypeInfo declaredTypeInfo, DkmInspectionContext inspectionContext, ReadOnlyCollection formatSpecifiers, string resultName, string resultFullName, DkmCompletionRoutine completionRoutine) { formatSpecifiers ??= Formatter.NoFormatSpecifiers; diff --git a/src/ExpressionEvaluator/Core/Test/FunctionResolver/Process.cs b/src/ExpressionEvaluator/Core/Test/FunctionResolver/Process.cs index adbf1368e2732..0938a96d9d009 100644 --- a/src/ExpressionEvaluator/Core/Test/FunctionResolver/Process.cs +++ b/src/ExpressionEvaluator/Core/Test/FunctionResolver/Process.cs @@ -13,7 +13,6 @@ internal sealed class Process : IDisposable { private readonly bool _shouldEnable; private readonly List _modules; - private int _shouldEnableRequests; internal Process(params Module[] modules) : this(true, modules) { @@ -25,11 +24,11 @@ internal Process(bool shouldEnable, params Module[] modules) _modules = new List(modules); } - internal int ShouldEnableRequests => _shouldEnableRequests; + internal int ShouldEnableRequests { get; private set; } internal bool ShouldEnableFunctionResolver() { - _shouldEnableRequests++; + ShouldEnableRequests++; return _shouldEnable; } diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrAppDomain.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrAppDomain.cs index a50c12786514c..e7de436d3e10e 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrAppDomain.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrAppDomain.cs @@ -15,26 +15,21 @@ namespace Microsoft.VisualStudio.Debugger.Clr { public class DkmClrAppDomain { - private readonly DkmClrRuntimeInstance _runtime; - internal DkmClrAppDomain(DkmClrRuntimeInstance runtime) { - _runtime = runtime; + RuntimeInstance = runtime; } - public DkmClrRuntimeInstance RuntimeInstance - { - get { return _runtime; } - } + public DkmClrRuntimeInstance RuntimeInstance { get; } public DkmClrModuleInstance FindClrModuleInstance(Guid mvid) { - return _runtime.FindClrModuleInstance(mvid); + return RuntimeInstance.FindClrModuleInstance(mvid); } public DkmClrModuleInstance[] GetClrModuleInstances() { - return _runtime.Modules; + return RuntimeInstance.Modules; } } } diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrModuleInstance.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrModuleInstance.cs index 7085d069cee6d..71a551d602fec 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrModuleInstance.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrModuleInstance.cs @@ -26,13 +26,12 @@ namespace Microsoft.VisualStudio.Debugger.Clr public class DkmClrModuleInstance : DkmModuleInstance { internal readonly Assembly Assembly; - private readonly DkmClrRuntimeInstance _runtimeInstance; private int _resolveTypeNameFailures; public DkmClrModuleInstance(DkmClrRuntimeInstance runtimeInstance, Assembly assembly, DkmModule module) : base(module) { - _runtimeInstance = runtimeInstance; + RuntimeInstance = runtimeInstance; this.Assembly = assembly; } @@ -41,12 +40,9 @@ public Guid Mvid get { return this.Assembly.Modules.First().ModuleVersionId; } } - public DkmClrRuntimeInstance RuntimeInstance - { - get { return _runtimeInstance; } - } + public DkmClrRuntimeInstance RuntimeInstance { get; } - public DkmProcess Process => _runtimeInstance.Process; + public DkmProcess Process => RuntimeInstance.Process; public DkmClrType ResolveTypeName(string typeName, ReadOnlyCollection typeArguments) { @@ -62,7 +58,7 @@ public DkmClrType ResolveTypeName(string typeName, ReadOnlyCollection ((TypeImpl)t.GetLmrType()).Type).ToArray(); type = type.MakeGenericType(typeArgs); } - return _runtimeInstance.GetType((TypeImpl)type); + return RuntimeInstance.GetType((TypeImpl)type); } internal int ResolveTypeNameFailures diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrRuntimeInstance.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrRuntimeInstance.cs index 0a7fdba1346b3..7dcd322250b85 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrRuntimeInstance.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrRuntimeInstance.cs @@ -32,8 +32,6 @@ public class DkmClrRuntimeInstance : DkmRuntimeInstance internal readonly Assembly[] Assemblies; internal readonly DkmClrModuleInstance[] Modules; - private readonly DkmClrModuleInstance _defaultModule; - private readonly DkmClrAppDomain _appDomain; // exactly one for now private readonly Dictionary _favoritesByTypeName; internal readonly GetMemberValueDelegate GetMemberValue; @@ -50,8 +48,8 @@ internal DkmClrRuntimeInstance( getModule ??= (r, a) => new DkmClrModuleInstance(r, a, (a != null) ? new DkmModule(a.GetName().Name + ".dll") : null); this.Assemblies = assemblies; this.Modules = assemblies.Select(a => getModule(this, a)).Where(m => m != null).ToArray(); - _defaultModule = getModule(this, null); - _appDomain = new DkmClrAppDomain(this); + DefaultModule = getModule(this, null); + DefaultAppDomain = new DkmClrAppDomain(this); this.GetMemberValue = getMemberValue; } @@ -61,28 +59,22 @@ internal DkmClrRuntimeInstance(Assembly[] assemblies, Dictionary m.Assembly == assembly) ?? _defaultModule; - return new DkmClrType(module, _appDomain, type, GetObjectFavoritesInfo(type)); + var module = this.Modules.FirstOrDefault(m => m.Assembly == assembly) ?? DefaultModule; + return new DkmClrType(module, DefaultAppDomain, type, GetObjectFavoritesInfo(type)); } internal DkmClrType GetType(System.Type type) { var assembly = type.Assembly; var module = this.Modules.First(m => m.Assembly == assembly); - return new DkmClrType(module, _appDomain, (TypeImpl)type, GetObjectFavoritesInfo((TypeImpl)type)); + return new DkmClrType(module, DefaultAppDomain, (TypeImpl)type, GetObjectFavoritesInfo((TypeImpl)type)); } internal DkmClrType GetType(string typeName, params System.Type[] typeArguments) @@ -93,7 +85,7 @@ internal DkmClrType GetType(string typeName, params System.Type[] typeArguments) var type = assembly.GetType(typeName); if (type != null) { - var result = new DkmClrType(module, _appDomain, (TypeImpl)type, GetObjectFavoritesInfo((TypeImpl)type)); + var result = new DkmClrType(module, DefaultAppDomain, (TypeImpl)type, GetObjectFavoritesInfo((TypeImpl)type)); if (typeArguments.Length > 0) { result = result.MakeGenericType(typeArguments.Select(this.GetType).ToArray()); @@ -132,7 +124,7 @@ private static bool IsMscorlib(Assembly assembly) internal DkmClrModuleInstance FindClrModuleInstance(Guid mvid) { - return this.Modules.FirstOrDefault(m => m.Mvid == mvid) ?? _defaultModule; + return this.Modules.FirstOrDefault(m => m.Mvid == mvid) ?? DefaultModule; } private DkmClrObjectFavoritesInfo GetObjectFavoritesInfo(Type type) diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrType.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrType.cs index 20339c168082e..83fbb2228f1c6 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrType.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrType.cs @@ -34,9 +34,6 @@ public class DkmClrType BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; - - private readonly DkmClrModuleInstance _module; - private readonly DkmClrAppDomain _appDomain; private readonly Type _lmrType; private readonly ReadOnlyCollection _evalAttributes; private readonly DkmClrObjectFavoritesInfo _favorites; @@ -44,8 +41,8 @@ public class DkmClrType internal DkmClrType(DkmClrModuleInstance module, DkmClrAppDomain appDomain, Type lmrType, DkmClrObjectFavoritesInfo favorites = null) { - _module = module; - _appDomain = appDomain; + ModuleInstance = module; + AppDomain = appDomain; _lmrType = lmrType; _evalAttributes = GetEvalAttributes(lmrType); _favorites = favorites; @@ -61,17 +58,14 @@ internal DkmClrType(DkmClrRuntimeInstance runtime, Type lmrType) : { } - public DkmClrAppDomain AppDomain - { - get { return _appDomain; } - } + public DkmClrAppDomain AppDomain { get; } public DkmClrType ElementType { get { var elementType = _lmrType.GetElementType(); - return (elementType == null) ? null : Create(_appDomain, elementType); + return (elementType == null) ? null : Create(AppDomain, elementType); } } @@ -83,8 +77,8 @@ internal System.Type UnderlyingType internal DkmClrType MakeGenericType(params DkmClrType[] genericArguments) { var type = new DkmClrType( - _module, - _appDomain, + ModuleInstance, + AppDomain, _lmrType.MakeGenericType(genericArguments.Select(t => t._lmrType).ToArray()), _favorites); type._lazyGenericArguments = new ReadOnlyCollection(genericArguments); @@ -94,8 +88,8 @@ internal DkmClrType MakeGenericType(params DkmClrType[] genericArguments) internal DkmClrType MakeArrayType() { return new DkmClrType( - _module, - _appDomain, + ModuleInstance, + AppDomain, _lmrType.MakeArrayType()); } @@ -131,7 +125,7 @@ public ReadOnlyCollection GenericArguments var typeArgs = _lmrType.GetGenericArguments(); var genericArgs = (typeArgs.Length == 0) ? s_emptyTypes - : new ReadOnlyCollection(typeArgs.Select(t => DkmClrType.Create(_appDomain, t)).ToArray()); + : new ReadOnlyCollection(typeArgs.Select(t => DkmClrType.Create(AppDomain, t)).ToArray()); Interlocked.CompareExchange(ref _lazyGenericArguments, genericArgs, null); } return _lazyGenericArguments; @@ -148,14 +142,11 @@ public ReadOnlyCollection GetEvalAttributes() return _evalAttributes; } - public DkmClrModuleInstance ModuleInstance - { - get { return _module; } - } + public DkmClrModuleInstance ModuleInstance { get; } public DkmClrRuntimeInstance RuntimeInstance { - get { return _module.RuntimeInstance; } + get { return ModuleInstance.RuntimeInstance; } } private string GetDebuggerDisplay() diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmEvaluateDebuggerDisplayStringAsyncResult.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmEvaluateDebuggerDisplayStringAsyncResult.cs index 2872a69573c0d..0ec59b007dfb4 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmEvaluateDebuggerDisplayStringAsyncResult.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmEvaluateDebuggerDisplayStringAsyncResult.cs @@ -14,8 +14,6 @@ namespace Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation { public readonly struct DkmEvaluateDebuggerDisplayStringAsyncResult { - private readonly string _result; - public DkmEvaluateDebuggerDisplayStringAsyncResult(string result) { if (result == null) @@ -23,9 +21,9 @@ public DkmEvaluateDebuggerDisplayStringAsyncResult(string result) throw new ArgumentNullException(nameof(result)); } - _result = result; + Result = result; } - public string Result { get { return _result; } } + public string Result { get; } } } diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmEvaluationAsyncResult.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmEvaluationAsyncResult.cs index bd59418d17897..3dd08c9628611 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmEvaluationAsyncResult.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmEvaluationAsyncResult.cs @@ -14,8 +14,6 @@ namespace Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation { public struct DkmEvaluationAsyncResult { - private readonly DkmEvaluationResult _result; - public DkmEvaluationAsyncResult(DkmEvaluationResult Result) : this() { @@ -24,12 +22,12 @@ public DkmEvaluationAsyncResult(DkmEvaluationResult Result) throw new ArgumentNullException(nameof(Result)); } - _result = Result; + this.Result = Result; } public int ErrorCode { get { throw new NotImplementedException(); } } - public readonly DkmEvaluationResult Result { get { return _result; } } + public readonly DkmEvaluationResult Result { get; } internal Exception Exception { get; set; } diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmInspectionSession.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmInspectionSession.cs index 6c7aa75250eda..da86707bc504b 100644 --- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmInspectionSession.cs +++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmInspectionSession.cs @@ -71,7 +71,7 @@ internal bool Equals(InstanceAndMethod other) internal Dispatcher(ImmutableArray items) { _implementations = items; - _calls = new ArrayBuilder(); + _calls = ArrayBuilder.GetInstance(); } internal TResult Invoke(object instance, MethodId method, Func f) 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/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/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..741cb2f524f5d 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; @@ -1198,6 +1199,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 @@ -2851,12 +2856,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 +2990,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 +3008,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/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.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/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/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 d19b1b31874da..cae243cd43f59 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.NonEnumTypeDeclarations, 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 3486545b978ae..f06ac0c2cc60f 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 9871ddf996ca2..a70a1873bb1c6 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.NonEnumTypeDeclarations, - 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/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs index f69678a6b1b9c..70ab88f8b6b8c 100644 --- a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs @@ -192,7 +192,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/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..39649800085d0 100644 --- a/src/Features/CSharpTest/EditAndContinue/ActiveStatementTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/ActiveStatementTests.cs @@ -3633,6 +3633,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 +3774,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 +5335,7 @@ struct Buffer4 } [Fact] - public void ForEach_Update_Nullable() + public void ForEach_Update_Nullable_Struct() { var src1 = @" class C @@ -5229,6 +5366,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 +5951,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/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..b09c53ff6a0df 100644 --- a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -8485,7 +8485,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 +10046,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 +10063,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")]), ]); } @@ -18783,6 +18783,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 +19647,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 +19666,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 +19776,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() { 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..68460c3dc4d30 100644 --- a/src/Features/CSharpTest/ReplaceMethodWithProperty/ReplaceMethodWithPropertyTests.cs +++ b/src/Features/CSharpTest/ReplaceMethodWithProperty/ReplaceMethodWithPropertyTests.cs @@ -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/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/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/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/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/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/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..8c07cb46ba314 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractSuppressionCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractSuppressionCodeAction.cs @@ -10,14 +10,12 @@ internal 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.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.RemoveSuppressionCodeAction_Pragma.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs index 8c519f3b4459a..9e1996d55623b 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs @@ -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/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..fa6848fd418c1 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoring.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoring.cs @@ -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..a7ff8d8d18381 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,7 +246,7 @@ 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); } 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/SyncNamespace/AbstractChangeNamespaceService.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs index cdc645c34fe07..e94836ac33f5f 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); } } 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/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/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/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/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 769cf5bc507d0..f3643b0c755b4 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. + + oldNode = oldNodes[i]; + Contract.ThrowIfNull(oldNode); - if (diagnostics != null) + // 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; } @@ -3185,8 +3239,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 +3408,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 +3679,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 +3718,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 +3732,7 @@ private static void AddInsertEditsForMemberAndAccessors(ArrayBuilder> 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..d68a41ce4349f 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs @@ -148,6 +148,7 @@ 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)); // 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..1f739596ea9d9 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); @@ -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..3f985f9080329 100644 --- a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs +++ b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs @@ -143,4 +143,5 @@ internal enum RudeEditKind : ushort ChangingAttribute = 116, ChangingNameOrSignatureOfActiveMember = 117, UpdateMightNotHaveAnyEffect = 118, + TypeUpdateAroundActiveStatement = 119, } 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/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/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/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/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.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.cs index 17094bd99dc8e..52f4f042a8e83 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.cs @@ -21,8 +21,6 @@ internal 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/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/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/ExtractMethod/AbstractSyntaxTriviaService.Result.cs b/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.Result.cs index ad61a7c9cd4b5..2ed954b5dc070 100644 --- a/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.Result.cs +++ b/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.Result.cs @@ -17,8 +17,6 @@ private 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/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/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index f892d1bed8689..5cec87490ebac 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}' @@ -499,6 +454,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 +511,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 +607,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 +631,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 +766,6 @@ This version used in: {2} Install version '{0}' - - Generate variable '{0}' - Classes @@ -914,9 +848,6 @@ This version used in: {2} (Unknown) - - Implement abstract class - Use framework type @@ -1252,12 +1183,6 @@ This version used in: {2} Target type matches - - Generate parameter '{0}' - - - Generate parameter '{0}' (and overrides/implementations) - in Source (attribute) @@ -1322,31 +1247,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 +1714,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 +2534,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 +3145,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 +3165,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/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/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/GenerateType/AbstractGenerateTypeService.Editor.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs index e1cee305dece0..769bd5dd72d90 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs @@ -480,12 +480,12 @@ private async Task> 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..6af8d2d605ad7 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs @@ -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(), 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/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs b/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs index b410e66ecaa13..c9354eb78ae23 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; @@ -33,6 +34,11 @@ internal class DecompilationMetadataAsSourceFileProvider(IImplementationAssembly { 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) 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/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/Microsoft.CodeAnalysis.Features.csproj b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj index ad1ceb9784462..f723a4ff711f4 100644 --- a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj +++ b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj @@ -84,6 +84,8 @@ + + @@ -113,11 +115,6 @@ - - @@ -145,9 +142,6 @@ - - - diff --git a/src/Features/Core/Portable/Options/EditorConfig/EditorConfigOptionsEnumerator.cs b/src/Features/Core/Portable/Options/EditorConfig/EditorConfigOptionsEnumerator.cs index 2e7fbb6e9aa0c..9a6cc0a29b86b 100644 --- a/src/Features/Core/Portable/Options/EditorConfig/EditorConfigOptionsEnumerator.cs +++ b/src/Features/Core/Portable/Options/EditorConfig/EditorConfigOptionsEnumerator.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.ImplementType; +using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.CodeAnalysis.ValidateFormatString; namespace Microsoft.CodeAnalysis.Options; @@ -40,12 +41,14 @@ 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, [ .. ImplementTypeOptionsStorage.EditorConfigOptions, - .. MemberDisplayOptionsStorage.EditorConfigOptions + .. MemberDisplayOptionsStorage.EditorConfigOptions, + .. SymbolSearchOptionsStorage.EditorConfigOptions, ]); yield return (WorkspacesResources.dot_NET_Coding_Conventions, 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/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/RQName/SimpleTree/SimpleGroupNode.cs b/src/Features/Core/Portable/RQName/SimpleTree/SimpleGroupNode.cs index 061c611c14c78..fee3d43ba7f2b 100644 --- a/src/Features/Core/Portable/RQName/SimpleTree/SimpleGroupNode.cs +++ b/src/Features/Core/Portable/RQName/SimpleTree/SimpleGroupNode.cs @@ -9,13 +9,11 @@ namespace Microsoft.CodeAnalysis.Features.RQName.SimpleTree; internal 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/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/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/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/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/SignatureHelpItems.cs b/src/Features/Core/Portable/SignatureHelp/SignatureHelpItems.cs index 040aa06149dcb..e56483dcfb77b 100644 --- a/src/Features/Core/Portable/SignatureHelp/SignatureHelpItems.cs +++ b/src/Features/Core/Portable/SignatureHelp/SignatureHelpItems.cs @@ -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/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/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/SymbolSearchUpdateEngine.Update.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.Update.cs index 8cae5c243f16f..c7fc3187b3e74 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.Update.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.Update.cs @@ -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/SyncNamespaces/AbstractSyncNamespacesService.cs b/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesService.cs index ecf0c6fcdbb95..5e5d63aaa56a4 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); } 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/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/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index 80b2136a163bb..d9626f8e62387 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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} @@ -2725,6 +2630,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 + Symbol search + + Symbols Symboly @@ -2735,16 +2645,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 +2710,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 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + Updating the type of {0} requires restarting the application. Aktualizace typu {0} vyžaduje restartování aplikace. @@ -3920,16 +3820,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 +3835,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 +3845,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 +4125,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 +4150,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 +4500,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..efa5ca40625b9 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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. @@ -2725,6 +2630,11 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Das Symbol wurde unter dem Assemblypfad „{0}“ gefunden + + Symbol search + Symbol search + + Symbols Symbole @@ -2735,16 +2645,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 +2710,6 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Ein nachgestelltes Komma ist unzulässig - - Type members - Type members - - Types: Typen: @@ -3025,6 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + Updating the type of {0} requires restarting the application. Das Aktualisieren des Typs von {0} erfordert einen Neustart der Anwendung. @@ -3920,16 +3820,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 +3835,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 +3845,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 +4125,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 +4150,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 +4500,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..e9402b2dd1524 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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} @@ -2725,6 +2630,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 + Symbol search + + Symbols Símbolos @@ -2735,16 +2645,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 +2710,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 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + Updating the type of {0} requires restarting the application. Para actualizar el tipo de {0} es necesario reiniciar la aplicación. @@ -3920,16 +3820,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 +3835,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 +3845,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 +4125,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 +4150,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 +4500,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..15f3753c083b5 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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 @@ -2725,6 +2630,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 + Symbol search + + Symbols Symboles @@ -2735,16 +2645,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 +2710,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 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the 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 +3820,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 +3835,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 +3845,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 +4125,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 +4150,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 +4500,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..c4f231f0df7c4 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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 @@ -2725,6 +2630,11 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Simbolo trovato nel percorso assembly '{0}' + + Symbol search + Symbol search + + Symbols Simboli @@ -2735,16 +2645,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 +2710,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 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + Updating the type of {0} requires restarting the application. Se si aggiorna il tipo di {0}, è necessario riavviare l'applicazione. @@ -3920,16 +3820,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 +3835,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 +3845,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 +4125,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 +4150,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 +4500,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..9d7a5edd64985 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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} 文字エスケープです @@ -2725,6 +2630,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of アセンブリ パス '{0}' にシンボルが見つかりました + + Symbol search + Symbol search + + Symbols シンボル @@ -2735,16 +2645,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 +2710,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 末尾にコンマは使用できない - - Type members - Type members - - Types: 型: @@ -3025,6 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + Updating the type of {0} requires restarting the application. {0} の種類を更新するには、アプリケーションを再起動する必要があります。 @@ -3920,16 +3820,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 +3835,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 +3845,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 +4125,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 +4150,6 @@ Do you want to continue? ソリューション - - TODO: dispose managed state (managed objects) - TODO: マネージド状態を破棄します (マネージド オブジェクト) - - - - TODO: set large fields to null - TODO: 大きなフィールドを null に設定します - - Compiler コンパイラ @@ -4660,11 +4500,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..1252d1891c69e 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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} 문자 이스케이프 @@ -2725,6 +2630,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 어셈블리 경로 '{0}'에서 기호를 찾음 + + Symbol search + Symbol search + + Symbols 기호 @@ -2735,16 +2645,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 +2710,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 후행 쉼표는 허용되지 않습니다. - - Type members - Type members - - Types: 형식: @@ -3025,6 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + Updating the type of {0} requires restarting the application. {0} 유형을 업데이트하려면 애플리케이션을 다시 시작해야 합니다. @@ -3920,16 +3820,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 +3835,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 +3845,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 +4125,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 +4150,6 @@ Do you want to continue? 솔루션 - - TODO: dispose managed state (managed objects) - TODO: 관리형 상태(관리형 개체)를 삭제합니다. - - - - TODO: set large fields to null - TODO: 큰 필드를 null로 설정합니다. - - Compiler 컴파일러 @@ -4660,11 +4500,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..815c94748be90 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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} @@ -2725,6 +2630,11 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Znaleziono symbol w ścieżce zestawu „{0}” + + Symbol search + Symbol search + + Symbols Symbole @@ -2735,16 +2645,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 +2710,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 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + Updating the type of {0} requires restarting the application. Aktualizacja typu elementu {0} wymaga ponownego uruchomienia aplikacji. @@ -3920,16 +3820,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 +3835,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 +3845,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 +4125,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 +4150,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 +4500,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..4e98f15df7c74 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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} @@ -2725,6 +2630,11 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Símbolo encontrado no caminho de montagem '{0}' + + Symbol search + Symbol search + + Symbols Símbolos @@ -2735,16 +2645,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 +2710,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 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + Updating the type of {0} requires restarting the application. Atualizar o tipo de {0} requer a reinicialização do aplicativo. @@ -3920,16 +3820,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 +3835,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 +3845,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 +4125,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 +4150,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 +4500,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..f83c487da8209 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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} @@ -2725,6 +2630,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Найден символ в пути сборки "{0}" + + Symbol search + Symbol search + + Symbols Символы @@ -2735,16 +2645,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 +2710,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Завершающая запятая не разрешена - - Type members - Type members - - Types: Типы: @@ -3025,6 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + Updating the type of {0} requires restarting the application. Для обновления типа {0} требуется перезапустить приложение. @@ -3920,16 +3820,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 +3835,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 +3845,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 +4125,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 +4150,6 @@ Do you want to continue? Решение - - TODO: dispose managed state (managed objects) - TODO: освободить управляемое состояние (управляемые объекты) - - - - TODO: set large fields to null - TODO: установить значение NULL для больших полей - - Compiler Компилятор @@ -4660,11 +4500,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..29932cae82242 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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çış @@ -2725,6 +2630,11 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri “{0}” derleme yolunda sembol bulundu + + Symbol search + Symbol search + + Symbols Semboller @@ -2735,16 +2645,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 +2710,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 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + 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 +3820,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 +3835,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 +3845,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 +4125,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 +4150,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 +4500,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..86a6fe05a210f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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} 字符转义不完整 @@ -2725,6 +2630,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 在程序集路径 "{0}" 中找到符号 + + Symbol search + Symbol search + + Symbols 符号 @@ -2735,16 +2645,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 +2710,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 不允许使用尾随逗号 - - Type members - Type members - - Types: 类型: @@ -3025,6 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + Updating the type of {0} requires restarting the application. 更新 {0} 的类型需要重启应用程序。 @@ -3920,16 +3820,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 +3835,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 +3845,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 +4125,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 +4150,6 @@ Do you want to continue? 解决方案 - - TODO: dispose managed state (managed objects) - TODO: 释放托管状态(托管对象) - - - - TODO: set large fields to null - TODO: 将大型字段设置为 null - - Compiler 编译器 @@ -4660,11 +4500,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..95bdd64c6f401 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -315,11 +315,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 +660,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 +820,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 +860,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 +870,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 +880,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} 字元逸出 @@ -2725,6 +2630,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 在組件路徑 '{0}' 中找到符號 + + Symbol search + Symbol search + + Symbols 符號 @@ -2735,16 +2645,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 +2710,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 尾端不得為逗號 - - Type members - Type members - - Types: 類型: @@ -3025,6 +2920,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. + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + + Updating the type of {0} requires restarting the application. 更新 {0} 的類型需要重新啟動應用程式。 @@ -3920,16 +3820,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 +3835,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 +3845,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 +4125,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 +4150,6 @@ Do you want to continue? 解決方案 - - TODO: dispose managed state (managed objects) - TODO: 處置受控狀態 (受控物件) - - - - TODO: set large fields to null - TODO: 將大型欄位設為 Null - - Compiler 編譯器 @@ -4660,11 +4500,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/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/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/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs b/src/Features/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs index 36df7d600bbcd..4e7271697ec57 100644 --- a/src/Features/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs +++ b/src/Features/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs @@ -23,7 +23,7 @@ public static CodeFixContext CreateCodeFixContext( OmniSharpCodeActionOptions options, #pragma warning restore IDE0060 // Remove unused parameter CancellationToken cancellationToken) - => new(document, span, diagnostics, registerCodeFix, CodeActionOptions.DefaultProvider, cancellationToken); + => new(document, span, diagnostics, registerCodeFix, cancellationToken); public static CodeAnalysis.CodeRefactorings.CodeRefactoringContext CreateCodeRefactoringContext( Document document, @@ -33,7 +33,7 @@ public static CodeAnalysis.CodeRefactorings.CodeRefactoringContext CreateCodeRef OmniSharpCodeActionOptions options, #pragma warning restore IDE0060 // Remove unused parameter CancellationToken cancellationToken) - => new(document, span, registerRefactoring, CodeActionOptions.DefaultProvider, cancellationToken); + => new(document, span, registerRefactoring, cancellationToken); public static FixAllContext CreateFixAllContext( Document? document, @@ -57,8 +57,7 @@ public static FixAllContext CreateFixAllContext( scope, codeActionEquivalenceKey, diagnosticIds, - fixAllDiagnosticProvider, - CodeActionOptions.DefaultProvider), + fixAllDiagnosticProvider), CodeAnalysisProgress.None, cancellationToken); } } 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 e41f856d301e2..f4f200567f50f 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"",""extension 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"",""extension 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/SemanticTokensTests.vb b/src/Features/Lsif/GeneratorTest/SemanticTokensTests.vb index 43f6a80c1dac2..c9ce9f1c63ee7 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..72c01a9a1a898 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] @@ -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/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..e37bf86c3b4ad 100644 --- a/src/Features/Test/FindUsages/DefinitionItemFactoryTests.cs +++ b/src/Features/Test/FindUsages/DefinitionItemFactoryTests.cs @@ -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..6bc6fba2cb68a 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 { 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/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..109cee82f9651 100644 --- a/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb @@ -2335,16 +2335,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 +2373,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 +2388,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/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/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/Interactive/HostProcess/x64/InteractiveHost64.csproj b/src/Interactive/HostProcess/x64/InteractiveHost64.csproj index 7bbf60b076672..0dde1d1cb34c7 100644 --- a/src/Interactive/HostProcess/x64/InteractiveHost64.csproj +++ b/src/Interactive/HostProcess/x64/InteractiveHost64.csproj @@ -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..79efde2fb521f 100644 --- a/src/Interactive/HostProcess/x86/InteractiveHost32.csproj +++ b/src/Interactive/HostProcess/x86/InteractiveHost32.csproj @@ -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/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..370e091f96577 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs @@ -43,14 +43,12 @@ 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[] - { + + _fileChangeContext = fileWatcher.CreateContext([ new(projectDirectory, ".cs"), new(projectDirectory, ".cshtml"), new(projectDirectory, ".razor") - }; - - _fileChangeContext = fileWatcher.CreateContext(watchedDirectories); + ]); _fileChangeContext.FileChanged += FileChangedContext_FileChanged; // Start watching for file changes for the project file as well 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/Microsoft.CodeAnalysis.LanguageServer.csproj b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj index 56ede6d5b150e..914f0485035d9 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj @@ -78,6 +78,7 @@ + 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/Protocol/Extensions/Extensions.cs b/src/LanguageServer/Protocol/Extensions/Extensions.cs index d9b8e4078f89f..2523b9c721708 100644 --- a/src/LanguageServer/Protocol/Extensions/Extensions.cs +++ b/src/LanguageServer/Protocol/Extensions/Extensions.cs @@ -243,5 +243,20 @@ 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; + } } } diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index 8a160dc30d3fc..79b5ab45911ba 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -21,6 +21,7 @@ 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; @@ -309,13 +310,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 +455,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(), @@ -582,6 +584,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) @@ -991,7 +1002,7 @@ static string GetStyledText(TaggedText taggedText, bool isInCodeBlock) return null; } - var spanMappingService = document.Services.GetService(); + var spanMappingService = document.DocumentServiceProvider.GetService(); if (spanMappingService == null) { return null; 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/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..da2a491dd33c1 100644 --- a/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_OpenDocument.cs +++ b/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_OpenDocument.cs @@ -28,7 +28,7 @@ public override async Task> GetDiagnosticsAsync(R 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) + if (services.GetService()?.SessionTracker is not { IsSessionActive: true } sessionStateTracker) { return []; } diff --git a/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs b/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs index b84fee77d2030..4e229286b1e7a 100644 --- a/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs +++ b/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs @@ -37,7 +37,7 @@ 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) + if (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 a6b78f13a58e8..0000000000000 --- a/src/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.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) - }; - - 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/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..d877472dfe24d 100644 --- a/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs +++ b/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs @@ -109,7 +109,15 @@ private ValueTask FilterLspTrackedDocumentsAsync( { if (documentUri is null || !trackedDocuments.ContainsKey(documentUri)) { - return notificationManager.SendRequestAsync(GetWorkspaceRefreshName(), cancellationToken); + try + { + return notificationManager.SendRequestAsync(GetWorkspaceRefreshName(), cancellationToken); + } + catch (StreamJsonRpc.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/Configuration/DidChangeConfigurationNotificationHandler.cs b/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler.cs index 07786e46a47de..914489a045c28 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++) { 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/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/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..d2ea413a2eec3 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,7 +77,7 @@ 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."); diff --git a/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs b/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs index bdfdaf086746d..1b23de6749170 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,7 +55,7 @@ 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( 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..a9fa355459e8c 100644 --- a/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs +++ b/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs @@ -138,7 +138,7 @@ public override async ValueTask OnReferencesFoundAsync(IAsyncEnumerable new RelatedDocumentsHandler(); +} + +[Method(VSInternalMethods.CopilotRelatedDocumentsName)] +internal sealed class RelatedDocumentsHandler + : ILspServiceRequestHandler, + ITextDocumentIdentifierHandler +{ + /// + /// Cache where we store the data produced by prior requests so that they can be returned if nothing of significance + /// changed. The version key is produced by combining the checksums for project options and + /// + private readonly VersionedPullCache<(Checksum parseOptionsChecksum, Checksum textChecksum)?> _versionedCache = new(nameof(RelatedDocumentsHandler)); + + public bool MutatesSolutionState => false; + public bool RequiresLSPSolution => true; + + private static async Task<(Checksum parseOptionsChecksum, Checksum textChecksum)> ComputeChecksumsAsync(Document document, CancellationToken cancellationToken) + { + var project = document.Project; + var parseOptionsChecksum = project.State.GetParseOptionsChecksum(); + + var documentChecksumState = await document.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); + var textChecksum = documentChecksumState.Text; + + return (parseOptionsChecksum, textChecksum); + } + + public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalRelatedDocumentParams requestParams) + => requestParams.TextDocument; + + /// + /// Retrieve the previous results we reported. Used so we can avoid resending data for unchanged files. + /// + private static ImmutableArray? GetPreviousResults(VSInternalRelatedDocumentParams requestParams) + => requestParams.PreviousResultId != null && requestParams.TextDocument != null + ? [new PreviousPullResult(requestParams.PreviousResultId, requestParams.TextDocument)] + // The client didn't provide us with a previous result to look for, so we can't lookup anything. + : null; + + public async Task HandleRequestAsync( + VSInternalRelatedDocumentParams requestParams, RequestContext context, CancellationToken cancellationToken) + { + context.TraceInformation($"{this.GetType()} started getting related documents"); + context.TraceInformation($"PreviousResultId={requestParams.PreviousResultId}"); + + 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 documentToPreviousParams = new Dictionary(); + if (requestParams.PreviousResultId != null) + documentToPreviousParams.Add(document, new PreviousPullResult(requestParams.PreviousResultId, requestParams.TextDocument)); + + var newResultId = await _versionedCache.GetNewResultIdAsync( + documentToPreviousParams, + document, + computeVersionAsync: async () => await ComputeChecksumsAsync(document, cancellationToken).ConfigureAwait(false), + cancellationToken).ConfigureAwait(false); + if (newResultId != null) + { + context.TraceInformation($"Version was changed for document: {document.FilePath}"); + + 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 + { + ResultId = newResultId, + FilePaths = relatedDocumentIds.Select(id => solution.GetRequiredDocument(id).FilePath).WhereNotNull().ToArray(), + }); + + return ValueTaskFactory.CompletedTask; + }, + cancellationToken).ConfigureAwait(false); + } + else + { + context.TraceInformation($"Version was unchanged for document: {document.FilePath}"); + + // Nothing changed between the last request and this one. Report a (null-file-paths, same-result-id) + // response to the client as that means they should just preserve the current related file paths they + // have for this file. + progress.Report(new VSInternalRelatedDocumentReport { ResultId = requestParams.PreviousResultId }); + } + + // 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/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/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/SpellCheck/AbstractSpellCheckingHandler.cs b/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs index f63aed313296e..d7fe19248adff 100644 --- a/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs +++ b/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs @@ -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; diff --git a/src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs b/src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs index d9cd5fa1a5768..0afa15c5e7c0f 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,53 +38,58 @@ 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 service = document.Project.Solution.Services.GetRequiredService(); + + return GetDocumentSymbolsAsync(document, useHierarchicalSymbols, service, cancellationToken); + } + internal static async Task> GetDocumentSymbolsAsync(Document document, bool useHierarchicalSymbols, ILspSymbolInformationCreationService symbolInformationCreationService, 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, symbolInformationCreationService)); foreach (var childItem in item.ChildItems) - symbols.AddIfNotNull(GetSymbolInformation(childItem, document, text, item.Text)); + symbols.AddIfNotNull(GetSymbolInformation(childItem, document, text, item.Text, symbolInformationCreationService)); } - } - 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, ILspSymbolInformationCreationService symbolInformationCreationService) { if (item is not RoslynNavigationBarItem.SymbolItem symbolItem || symbolItem.Location.InDocumentInfo == null) return null; - var service = document.Project.Solution.Services.GetRequiredService(); - return service.Create( + return symbolInformationCreationService.Create( GetDocumentSymbolName(item.Text), containerName, ProtocolConversions.GlyphToSymbolKind(item.Glyph), @@ -118,7 +123,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 index ebc72add98679..9eaddbba460a9 100644 --- a/src/LanguageServer/Protocol/Handler/Symbols/ILspSymbolInformationCreationService.cs +++ b/src/LanguageServer/Protocol/Handler/Symbols/ILspSymbolInformationCreationService.cs @@ -28,11 +28,13 @@ public DefaultLspSymbolInformationCreationService() public SymbolInformation Create(string name, string? containerName, LSP.SymbolKind kind, LSP.Location location, Glyph glyph) => new() +#pragma warning disable CS0618 // SymbolInformation is obsolete, need to switch to DocumentSymbol/WorkspaceSymbol { 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 bfd7d9941781d..b3486aa0d31ee 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, @@ -47,13 +48,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, @@ -63,7 +67,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( 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..e52be3d89dcf5 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalRelatedDocumentParams.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. + +namespace Roslyn.LanguageServer.Protocol +{ + using System; + using System.Text.Json.Serialization; + + /// + /// Parameter for copilot/_related_documents. + /// + internal sealed class VSInternalRelatedDocumentParams : VSInternalStreamingParams, IPartialResultParams + { + /// + /// 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 + { + /// + /// Gets or sets the server-generated version number for the related documents result. This is treated as a + /// black box by the client: it is stored on the client for each textDocument and sent back to the server when + /// requesting related documents. The server can use this result ID to avoid resending results + /// that had previously been sent. + /// + [JsonPropertyName("_vs_resultId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? ResultId { get; set; } + + [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..35c7dc41e322e 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,39 @@ 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); + } + // 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..0dbbfe966ee2c 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,27 +25,31 @@ 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 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(documentFilePath, languageId); if (languageInformation == null) { @@ -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..d49ab8c07e63e 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); @@ -238,7 +288,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 +308,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; diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.cs.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.cs.xlf index c1e6b6b4e7cac..c47c1b32c70f3 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..a53ede252ea69 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..c15618b613a02 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..857632098575f 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..01330db80711b 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..89efb2f358b63 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..551dccb164487 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..2008e1e8e73ee 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..dd8c02b8a9ba4 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..044be3dc3212b 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..9d41e59818118 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..9b7cfafe1a251 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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..86709c83cd70c 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} + Unable to deserialize FormattingOptions. Invalid token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Unable to deserialize FormattingOptions as it ended unexpectedly + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize FormattingOptions. Missing required property: {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/Completion/CompletionResolveTests.cs b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs index d03e70a4b2c26..1e8fb37e9479b 100644 --- a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs @@ -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 21d93d5e6d634..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 } }; @@ -117,6 +117,7 @@ public void VerifyLspClientOptionNames() "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,7 +145,8 @@ 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" + "projects.dotnet_enable_automatic_restore", + "navigation.dotnet_navigate_to_source_link_and_embedded_sources" }; AssertEx.SetEqual(expectedNames, actualNames); 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..be6f6aa97321f 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)); 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..d0be59f92a78b 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs @@ -978,7 +978,7 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithRunCodeAnalysisAndFS } [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 {"; @@ -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 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); + Assert.Empty(results[0].Diagnostics); + Assert.True(results[1].Diagnostics.Single().Message.Contains("Source generator failed")); + } + [Theory, CombinatorialData] public async Task TestWorkspaceTodoForClosedFilesWithFSAOffAndTodoOff(bool mutatingLspWorkspace) { diff --git a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs index 3bafb1e06a808..2c2164f5ad65d 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; @@ -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) { 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..a9579caff7969 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,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, WorkItem("https://github.com/dotnet/vscode-csharp/issues/6577")] @@ -449,7 +449,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/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..be4d17c5e185e --- /dev/null +++ b/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.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; +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.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/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..02502fef59e14 --- /dev/null +++ b/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs @@ -0,0 +1,186 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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, + string? previousResultId = null, + bool useProgress = false) + { + BufferedProgress? progress = useProgress ? BufferedProgress.Create(null) : null; + var spans = await testLspServer.ExecuteRequestAsync( + VSInternalMethods.CopilotRelatedDocumentsName, + new VSInternalRelatedDocumentParams + { + TextDocument = new TextDocumentIdentifier { Uri = uri }, + PreviousResultId = previousResultId, + 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 TestResultIds(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); + + AssertJsonEquals(results1, new VSInternalRelatedDocumentReport[] + { + new() + { + ResultId = "RelatedDocumentsHandler:0", + FilePaths = [project.Documents.Last().FilePath!], + } + }); + + // Calling again, without a change, should return the old result id and no filepaths. + var results2 = await RunGetRelatedDocumentsAsync( + testLspServer, + project.Documents.First().GetURI(), + previousResultId: results1.Single().ResultId, + useProgress: useProgress); + + AssertJsonEquals(results2, new VSInternalRelatedDocumentReport[] + { + new() + { + ResultId = "RelatedDocumentsHandler:0", + FilePaths = null, + } + }); + } +} 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..463b5a8774043 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); @@ -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); @@ -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); @@ -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); @@ -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); diff --git a/src/LanguageServer/ProtocolUnitTests/Symbols/DocumentSymbolsTests.cs b/src/LanguageServer/ProtocolUnitTests/Symbols/DocumentSymbolsTests.cs index 738c127bcc2be..39aac2145919f 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] @@ -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..d5ab8a0cda616 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); } @@ -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/Workspaces/LspWorkspaceManagerTests.cs b/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs index ae4fc945289ff..3998238e041dd 100644 --- a/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs @@ -55,7 +55,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 +107,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")); 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/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/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs index e1da918c194b7..b3f6181913861 100644 --- a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs +++ b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs @@ -161,7 +161,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)); 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/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..7a36b5d47c0f2 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSymbols.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Roslyn.LanguageServer.Protocol; +using Roslyn.Utilities; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; + +internal static class DocumentSymbols +{ + public static Task> GetDocumentSymbolsAsync(Document document, bool useHierarchicalSymbols, CancellationToken cancellationToken) + { + // The symbol information service in Roslyn lives in EditorFeatures and has VS dependencies. for glyph images, + // so isn't available in OOP. The default implementation is available in OOP, but not in the Roslyn MEF composition, + // so we have to provide our own. + return DocumentSymbolsHandler.GetDocumentSymbolsAsync(document, useHierarchicalSymbols, RazorLspSymbolInformationCreationService.Instance, cancellationToken); + } + + private sealed class RazorLspSymbolInformationCreationService : ILspSymbolInformationCreationService + { + public static readonly RazorLspSymbolInformationCreationService Instance = new(); + + public SymbolInformation Create(string name, string? containerName, LSP.SymbolKind kind, LSP.Location location, Glyph glyph) +#pragma warning disable CS0618 // SymbolInformation is obsolete + => new() + { + Name = name, + ContainerName = containerName, + Kind = kind, + Location = location, + }; +#pragma warning restore CS0618 + } +} 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/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/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/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/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/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/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 e1a5fe73e0390..bfd1d41affb48 100644 --- a/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs +++ b/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs @@ -115,7 +115,7 @@ 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. 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/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/Options/VisualStudioOptionStorage.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs index d78ebedc11089..8ceae9cd6694d 100644 --- a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs +++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs @@ -406,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/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 5f79a54680d57..ee727aef713a9 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); @@ -687,7 +686,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); } } @@ -706,7 +705,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; @@ -761,7 +760,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; @@ -771,7 +770,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); @@ -850,13 +849,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..4e4d52b151282 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -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} @@ -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. + příklad + {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. + identifikátor + {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..871cdfcdf0c23 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -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}" @@ -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. + Beispiel + {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. + Bezeichner + {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..a7edf4676c5a5 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -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} @@ -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. + ejemplo + {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. + identificador + {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..c8738b0d16763 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -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. + exemple + {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. + identificateur + {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..68fd9218ddb30 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -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} @@ -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. + esempio + {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. + identificatore + {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..55910dac7144e 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -1237,11 +1237,6 @@ 変更のプレビュー - - Roslyn save command handler - Roslyn 保存コマンド ハンドラー - - Run Code Analysis on {0} {0} で Code Analysis を実行 @@ -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. + + {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}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index 43efd7be1e16a..d979c2e3b356b 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -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. + + {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}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 147bef38e3fe2..2f69716aeb41e 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -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} @@ -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. + przykład + {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. + identyfikator + {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..f564cfc299a9d 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -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. + exemplo + {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. + identificador + {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..23989f5d20ce6 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -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. + пример + {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}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index 7b3cb41e022dc..e39e7180043f9 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -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. + örnek + {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. + tanımlayıcı + {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..02316ae23f502 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -1237,11 +1237,6 @@ 预览更改 - - Roslyn save command handler - Roslyn 保存命令处理程序 - - Run Code Analysis on {0} 对 {0} 运行 Code Analysis @@ -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. + 示例 + {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}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index e1e5394876d08..fb25fdd6a175e 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -1237,11 +1237,6 @@ 檢閱變更 - - Roslyn save command handler - Roslyn 儲存命令處理常式 - - Run Code Analysis on {0} 對 {0} 執行 Code Analysis @@ -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. + 範例 + {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}' 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 d90125d210f88..33c67f60f3bd7 100644 --- a/src/VisualStudio/Core/Test/Options/BasicEditorConfigGeneratorTests.vb +++ b/src/VisualStudio/Core/Test/Options/BasicEditorConfigGeneratorTests.vb @@ -43,6 +43,9 @@ 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 #### # Organize usings @@ -193,6 +196,9 @@ 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 #### # Organize usings diff --git a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb index 6162a1350730b..e3be0cb90efd8 100644 --- a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb +++ b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb @@ -41,6 +41,9 @@ 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 #### # Organize usings @@ -297,6 +300,9 @@ 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 #### # Organize usings 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/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/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 e6c8670ed7732..ebd37f701c177 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs @@ -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,8 @@ public FSharpEditorInlineRenameService( _service = service; } + public bool IsEnabled => true; + public Task>> GetRenameContextAsync(IInlineRenameInfo inlineRenameInfo, IInlineRenameLocationSet inlineRenameLocationSet, CancellationToken cancellationToken) { return Task.FromResult(ImmutableDictionary>.Empty); 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/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..fd6044eae7b7a 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, ["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 215018e9044bd..100c09ac83168 100644 --- a/src/VisualStudio/Xaml/Impl/Features/InlineRename/XamlEditorInlineRenameService.cs +++ b/src/VisualStudio/Xaml/Impl/Features/InlineRename/XamlEditorInlineRenameService.cs @@ -30,6 +30,8 @@ public XamlEditorInlineRenameService(IXamlRenameInfoService renameService) _renameService = renameService; } + public bool IsEnabled => true; + public Task>> GetRenameContextAsync(IInlineRenameInfo inlineRenameInfo, IInlineRenameLocationSet inlineRenameLocationSet, CancellationToken cancellationToken) { return Task.FromResult(ImmutableDictionary>.Empty); 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/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/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/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/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj b/src/Workspaces/Core/MSBuild.BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj index 2044a92f4e678..c4b8b1699e9be 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/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/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/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/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/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/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/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/Options/DocumentOptionSet.cs b/src/Workspaces/Core/Portable/Options/DocumentOptionSet.cs index 3cb64bfb637a5..cd386dd29bd62 100644 --- a/src/Workspaces/Core/Portable/Options/DocumentOptionSet.cs +++ b/src/Workspaces/Core/Portable/Options/DocumentOptionSet.cs @@ -20,7 +20,6 @@ public sealed class DocumentOptionSet : OptionSet { private readonly OptionSet _underlyingOptions; private readonly StructuredAnalyzerConfigOptions? _configOptions; - private readonly string _language; /// /// Cached internal values read from or . @@ -34,13 +33,13 @@ internal DocumentOptionSet(StructuredAnalyzerConfigOptions? configOptions, Optio private DocumentOptionSet(StructuredAnalyzerConfigOptions? configOptions, OptionSet underlyingOptions, string language, ImmutableDictionary values) { - _language = language; + Language = language; _configOptions = configOptions; _underlyingOptions = underlyingOptions; _values = values; } - internal string Language => _language; + internal string Language { get; } [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/30819", AllowLocks = false)] internal override object? GetInternalOptionValue(OptionKey optionKey) @@ -89,14 +88,14 @@ private bool TryGetAnalyzerConfigOption(OptionKey optionKey, out object? value) } public T GetOption(PerLanguageOption option) - => GetOption(option, _language); + => GetOption(option, Language); internal override OptionSet WithChangedOptionInternal(OptionKey optionKey, object? internalValue) - => new DocumentOptionSet(_configOptions, _underlyingOptions, _language, _values.SetItem(optionKey, internalValue)); + => new DocumentOptionSet(_configOptions, _underlyingOptions, Language, _values.SetItem(optionKey, internalValue)); /// /// Creates a new that contains the changed value. /// public DocumentOptionSet WithChangedOption(PerLanguageOption option, T value) - => (DocumentOptionSet)WithChangedOption(option, _language, value); + => (DocumentOptionSet)WithChangedOption(option, Language, value); } diff --git a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs index a8e2021cdc3b2..e3b8e60784b30 100644 --- a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs +++ b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs @@ -188,7 +188,7 @@ public bool SetGlobalOptions(ImmutableArray> o private bool SetGlobalOptions(OneOrMany> options) { - var changedOptions = new ArrayBuilder<(OptionKey2, object?)>(options.Count); + using var _ = ArrayBuilder<(OptionKey2, object?)>.GetInstance(options.Count, out var changedOptions); var persisters = GetOptionPersisters(); lock (_gate) diff --git a/src/Workspaces/Core/Portable/OrganizeImports/OrganizeImportsOptions.cs b/src/Workspaces/Core/Portable/OrganizeImports/OrganizeImportsOptionsProviders.cs similarity index 67% rename from src/Workspaces/Core/Portable/OrganizeImports/OrganizeImportsOptions.cs rename to src/Workspaces/Core/Portable/OrganizeImports/OrganizeImportsOptionsProviders.cs index 5a1e43b672b93..1d929d73dc61d 100644 --- a/src/Workspaces/Core/Portable/OrganizeImports/OrganizeImportsOptions.cs +++ b/src/Workspaces/Core/Portable/OrganizeImports/OrganizeImportsOptionsProviders.cs @@ -2,30 +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.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Options; 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(); -} - internal static class OrganizeImportsOptionsProviders { public static OrganizeImportsOptions GetOrganizeImportsOptions(this IOptionsReader options, string language) diff --git a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt index 8b137891791fe..2ebc1a3610226 100644 --- a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt @@ -1 +1,3 @@ - +Microsoft.CodeAnalysis.ProjectInfo.WithId(Microsoft.CodeAnalysis.ProjectId id) -> Microsoft.CodeAnalysis.ProjectInfo +virtual Microsoft.CodeAnalysis.Host.HostLanguageServices.Dispose() -> void +virtual Microsoft.CodeAnalysis.Host.HostWorkspaceServices.Dispose() -> void diff --git a/src/Workspaces/Core/Portable/Remote/IRemoteHostClientProvider.cs b/src/Workspaces/Core/Portable/Remote/IRemoteHostClientProvider.cs index d2633186e39a1..35694b428f142 100644 --- a/src/Workspaces/Core/Portable/Remote/IRemoteHostClientProvider.cs +++ b/src/Workspaces/Core/Portable/Remote/IRemoteHostClientProvider.cs @@ -17,4 +17,10 @@ internal interface IRemoteHostClientProvider : IWorkspaceService /// Get to current RemoteHost /// Task TryGetRemoteHostClientAsync(CancellationToken cancellationToken); + + /// + /// Allows a caller to wait until the remote host client is is first create, without itself kicking off the work to + /// spawn the remote host and make the client itself. + /// + Task WaitForClientCreationAsync(CancellationToken cancellationToken); } diff --git a/src/Workspaces/Core/Portable/Remote/ISerializerService.cs b/src/Workspaces/Core/Portable/Remote/ISerializerService.cs index f56f5f0a89417..ece3b937859a0 100644 --- a/src/Workspaces/Core/Portable/Remote/ISerializerService.cs +++ b/src/Workspaces/Core/Portable/Remote/ISerializerService.cs @@ -11,9 +11,6 @@ namespace Microsoft.CodeAnalysis.Serialization; internal interface ISerializerService : IWorkspaceService { void Serialize(object value, ObjectWriter writer, CancellationToken cancellationToken); - - void SerializeParseOptions(ParseOptions options, ObjectWriter writer); - object Deserialize(WellKnownSynchronizationKind kind, ObjectReader reader, CancellationToken cancellationToken); Checksum CreateChecksum(object value, CancellationToken cancellationToken); diff --git a/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs b/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs index eaf4a87232135..0c51bf0d12c80 100644 --- a/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs +++ b/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs @@ -19,6 +19,15 @@ internal abstract class RemoteHostClient : IDisposable { public abstract void Dispose(); + public static Task WaitForClientCreationAsync(Workspace workspace, CancellationToken cancellationToken) + { + var service = workspace.Services.GetService(); + if (service == null) + return Task.CompletedTask; + + return service.WaitForClientCreationAsync(cancellationToken); + } + public static Task TryGetClientAsync(Project project, CancellationToken cancellationToken) { if (!RemoteSupportedLanguages.IsSupported(project.Language)) diff --git a/src/Workspaces/Core/Portable/Rename/Renamer.cs b/src/Workspaces/Core/Portable/Rename/Renamer.cs index 1684a8d1f27e1..ff7be7c19f700 100644 --- a/src/Workspaces/Core/Portable/Rename/Renamer.cs +++ b/src/Workspaces/Core/Portable/Rename/Renamer.cs @@ -106,7 +106,7 @@ public static async Task RenameDocumentAsync( if (document == null) throw new ArgumentNullException(nameof(document)); - if (document.Services.GetService() != null) + if (document.DocumentServiceProvider.GetService() != null) { // Don't advertise that we can file rename generated documents that map to a different file. return new RenameDocumentActionSet([], document.Id, document.Name, [.. document.Folders], options); diff --git a/src/Workspaces/Core/Portable/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs b/src/Workspaces/Core/Portable/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs index 03bbe1438ce93..0d4712b4ce423 100644 --- a/src/Workspaces/Core/Portable/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs +++ b/src/Workspaces/Core/Portable/SemanticModelReuse/AbstractSemanticModelReuseLanguageService.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -105,7 +106,9 @@ protected SyntaxNode GetPreviousBodyNode(SyntaxNode previousRoot, SyntaxNode cur } else { - var currentMembers = this.SyntaxFacts.GetMethodLevelMembers(currentRoot); + using var pooledCurrentMembers = this.SyntaxFacts.GetMethodLevelMembers(currentRoot); + var currentMembers = pooledCurrentMembers.Object; + var index = currentMembers.IndexOf(currentBodyNode); if (index < 0) { @@ -113,7 +116,9 @@ protected SyntaxNode GetPreviousBodyNode(SyntaxNode previousRoot, SyntaxNode cur return null; } - var previousMembers = this.SyntaxFacts.GetMethodLevelMembers(previousRoot); + using var pooledPreviousMembers = this.SyntaxFacts.GetMethodLevelMembers(previousRoot); + var previousMembers = pooledPreviousMembers.Object; + if (currentMembers.Count != previousMembers.Count) { Debug.Fail("Member count shouldn't have changed as there were no top level edits."); diff --git a/src/Workspaces/Core/Portable/Serialization/SerializedMetadataReference.cs b/src/Workspaces/Core/Portable/Serialization/SerializedPortableExecutableReference.cs similarity index 89% rename from src/Workspaces/Core/Portable/Serialization/SerializedMetadataReference.cs rename to src/Workspaces/Core/Portable/Serialization/SerializedPortableExecutableReference.cs index 230bb0ddec317..da2315e4756e3 100644 --- a/src/Workspaces/Core/Portable/Serialization/SerializedMetadataReference.cs +++ b/src/Workspaces/Core/Portable/Serialization/SerializedPortableExecutableReference.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.Serialization; internal partial class SerializerService { [DebuggerDisplay("{" + nameof(Display) + ",nq}")] - private sealed class SerializedMetadataReference : PortableExecutableReference, ISupportTemporaryStorage + private sealed class SerializedPortableExecutableReference : PortableExecutableReference, ISupportTemporaryStorage { private readonly Metadata _metadata; private readonly ImmutableArray _storageHandles; @@ -24,7 +24,7 @@ private sealed class SerializedMetadataReference : PortableExecutableReference, public IReadOnlyList StorageHandles => _storageHandles; - public SerializedMetadataReference( + public SerializedPortableExecutableReference( MetadataReferenceProperties properties, string? fullPath, Metadata metadata, @@ -49,7 +49,7 @@ protected override Metadata GetMetadataImpl() => _metadata; protected override PortableExecutableReference WithPropertiesImpl(MetadataReferenceProperties properties) - => new SerializedMetadataReference(properties, FilePath, _metadata, _storageHandles, _provider); + => new SerializedPortableExecutableReference(properties, FilePath, _metadata, _storageHandles, _provider); public override string ToString() { @@ -57,7 +57,7 @@ public override string ToString() var modules = GetModules(metadata); return $""" - {nameof(SerializedMetadataReference)} + {nameof(PortableExecutableReference)} FilePath={this.FilePath} Kind={this.Properties.Kind} Aliases={this.Properties.Aliases.Join(",")} diff --git a/src/Workspaces/Core/Portable/Serialization/SerializerService.cs b/src/Workspaces/Core/Portable/Serialization/SerializerService.cs index fac5e87175dab..94a4572463837 100644 --- a/src/Workspaces/Core/Portable/Serialization/SerializerService.cs +++ b/src/Workspaces/Core/Portable/Serialization/SerializerService.cs @@ -4,10 +4,8 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; -using System.Diagnostics; using System.Linq; using System.Runtime.Versioning; using System.Threading; @@ -15,25 +13,21 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Serialization; -#if NETCOREAPP +#if NET [SupportedOSPlatform("windows")] #endif -internal partial class SerializerService : ISerializerService +[method: Obsolete(MefConstruction.FactoryMethodMessage, error: true)] +internal partial class SerializerService(SolutionServices workspaceServices) : ISerializerService { [ExportWorkspaceServiceFactory(typeof(ISerializerService), layer: ServiceLayer.Default), Shared] - internal sealed class Factory : IWorkspaceServiceFactory + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + internal sealed class Factory() : IWorkspaceServiceFactory { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public Factory() - { - } - [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) => new SerializerService(workspaceServices.SolutionServices); @@ -41,30 +35,17 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) private static readonly Func s_logKind = k => k.ToString(); - private readonly SolutionServices _workspaceServices; + // Serialization to temporary storage is only involved when we have a remote process. Which is only in VS. So the + // type of the storage service here is well known. However the serializer is created in other cases (e.g. to + // compute project state checksums). So lazily instantiate the storage service to avoid attempting to get the + // TemporaryStorageService when not available. - private readonly Lazy _storageService; - private readonly ITextFactoryService _textService; - private readonly IDocumentationProviderService? _documentationService; - private readonly IAnalyzerAssemblyLoaderProvider _analyzerLoaderProvider; - - private readonly ConcurrentDictionary _lazyLanguageSerializationService; - - [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] - private protected SerializerService(SolutionServices workspaceServices) - { - _workspaceServices = workspaceServices; + private readonly Lazy _storageService = new(() => (TemporaryStorageService)workspaceServices.GetRequiredService()); + private readonly ITextFactoryService _textService = workspaceServices.GetRequiredService(); + private readonly IDocumentationProviderService? _documentationService = workspaceServices.GetService(); + private readonly IAnalyzerAssemblyLoaderProvider _analyzerLoaderProvider = workspaceServices.GetRequiredService(); - // Serialization to temporary storage is only involved when we have a remote process. Which is only in VS. So the type of the - // storage service here is well known. However the serializer is created in other cases (e.g. to compute project state checksums). - // So lazily instantiate the storage service to avoid attempting to get the TemporaryStorageService when not available. - _storageService = new Lazy(() => (TemporaryStorageService)workspaceServices.GetRequiredService()); - _textService = workspaceServices.GetRequiredService(); - _analyzerLoaderProvider = workspaceServices.GetRequiredService(); - _documentationService = workspaceServices.GetService(); - - _lazyLanguageSerializationService = new ConcurrentDictionary(concurrencyLevel: 2, capacity: _workspaceServices.SupportedLanguages.Count()); - } + private readonly ConcurrentDictionary _lazyLanguageSerializationService = new(concurrencyLevel: 2, capacity: workspaceServices.SupportedLanguages.Count()); public Checksum CreateChecksum(object value, CancellationToken cancellationToken) { @@ -74,11 +55,6 @@ public Checksum CreateChecksum(object value, CancellationToken cancellationToken { cancellationToken.ThrowIfCancellationRequested(); - if (value is IChecksummedObject checksummedObject) - { - return checksummedObject.Checksum; - } - switch (kind) { case WellKnownSynchronizationKind.CompilationOptions: @@ -89,10 +65,10 @@ public Checksum CreateChecksum(object value, CancellationToken cancellationToken return Checksum.Create(value, this, cancellationToken); case WellKnownSynchronizationKind.MetadataReference: - return CreateChecksum((MetadataReference)value, cancellationToken); + return CreateChecksum((MetadataReference)value); case WellKnownSynchronizationKind.AnalyzerReference: - return CreateChecksum((AnalyzerReference)value, cancellationToken); + return CreateChecksum((AnalyzerReference)value); case WellKnownSynchronizationKind.SerializableSourceText: throw new InvalidOperationException("Clients can already get a checksum directly from a SerializableSourceText"); @@ -141,15 +117,15 @@ public void Serialize(object value, ObjectWriter writer, CancellationToken cance return; case WellKnownSynchronizationKind.ProjectReference: - SerializeProjectReference((ProjectReference)value, writer, cancellationToken); + SerializeProjectReference((ProjectReference)value, writer); return; case WellKnownSynchronizationKind.MetadataReference: - SerializeMetadataReference((MetadataReference)value, writer, cancellationToken); + SerializeMetadataReference((MetadataReference)value, writer); return; case WellKnownSynchronizationKind.AnalyzerReference: - SerializeAnalyzerReference((AnalyzerReference)value, writer, cancellationToken: cancellationToken); + SerializeAnalyzerReference((AnalyzerReference)value, writer); return; case WellKnownSynchronizationKind.SerializableSourceText: @@ -274,8 +250,8 @@ public object Deserialize(WellKnownSynchronizationKind kind, ObjectReader reader WellKnownSynchronizationKind.CompilationOptions => DeserializeCompilationOptions(reader, cancellationToken), WellKnownSynchronizationKind.ParseOptions => DeserializeParseOptions(reader, cancellationToken), WellKnownSynchronizationKind.ProjectReference => DeserializeProjectReference(reader, cancellationToken), - WellKnownSynchronizationKind.MetadataReference => DeserializeMetadataReference(reader, cancellationToken), - WellKnownSynchronizationKind.AnalyzerReference => DeserializeAnalyzerReference(reader, cancellationToken), + WellKnownSynchronizationKind.MetadataReference => DeserializeMetadataReference(reader), + WellKnownSynchronizationKind.AnalyzerReference => DeserializeAnalyzerReference(reader), WellKnownSynchronizationKind.SerializableSourceText => SerializableSourceText.Deserialize(reader, _storageService.Value, _textService, cancellationToken), WellKnownSynchronizationKind.SourceGeneratorExecutionVersionMap => SourceGeneratorExecutionVersionMap.Deserialize(reader), WellKnownSynchronizationKind.FallbackAnalyzerOptions => ReadFallbackAnalyzerOptions(reader), @@ -285,7 +261,7 @@ public object Deserialize(WellKnownSynchronizationKind kind, ObjectReader reader } private IOptionsSerializationService GetOptionsSerializationService(string languageName) - => _lazyLanguageSerializationService.GetOrAdd(languageName, n => _workspaceServices.GetLanguageServices(n).GetRequiredService()); + => _lazyLanguageSerializationService.GetOrAdd(languageName, n => workspaceServices.GetLanguageServices(n).GetRequiredService()); public Checksum CreateParseOptionsChecksum(ParseOptions value) => Checksum.Create((value, @this: this), static (tuple, writer) => tuple.@this.SerializeParseOptions(tuple.value, writer)); diff --git a/src/Workspaces/Core/Portable/Serialization/SerializerService_Asset.cs b/src/Workspaces/Core/Portable/Serialization/SerializerService_Asset.cs index ebedde5f5e949..5127abb995008 100644 --- a/src/Workspaces/Core/Portable/Serialization/SerializerService_Asset.cs +++ b/src/Workspaces/Core/Portable/Serialization/SerializerService_Asset.cs @@ -64,10 +64,8 @@ private ParseOptions DeserializeParseOptions(ObjectReader reader, CancellationTo return service.ReadParseOptionsFrom(reader, cancellationToken); } - private static void SerializeProjectReference(ProjectReference reference, ObjectWriter writer, CancellationToken cancellationToken) + private static void SerializeProjectReference(ProjectReference reference, ObjectWriter writer) { - cancellationToken.ThrowIfCancellationRequested(); - reference.ProjectId.WriteTo(writer); writer.WriteArray(reference.Aliases, static (w, a) => w.WriteString(a)); writer.WriteBoolean(reference.EmbedInteropTypes); @@ -84,27 +82,15 @@ private static ProjectReference DeserializeProjectReference(ObjectReader reader, return new ProjectReference(projectId, aliases.ToImmutableArrayOrEmpty(), embedInteropTypes); } - private void SerializeMetadataReference(MetadataReference reference, ObjectWriter writer, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - WriteMetadataReferenceTo(reference, writer, cancellationToken); - } + private void SerializeMetadataReference(MetadataReference reference, ObjectWriter writer) + => WriteMetadataReferenceTo(reference, writer); - private MetadataReference DeserializeMetadataReference(ObjectReader reader, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - return ReadMetadataReferenceFrom(reader, cancellationToken); - } + private MetadataReference DeserializeMetadataReference(ObjectReader reader) + => ReadMetadataReferenceFrom(reader); - private void SerializeAnalyzerReference(AnalyzerReference reference, ObjectWriter writer, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - WriteAnalyzerReferenceTo(reference, writer, cancellationToken); - } + private void SerializeAnalyzerReference(AnalyzerReference reference, ObjectWriter writer) + => WriteAnalyzerReferenceTo(reference, writer); - private AnalyzerReference DeserializeAnalyzerReference(ObjectReader reader, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - return ReadAnalyzerReferenceFrom(reader, cancellationToken); - } + private AnalyzerReference DeserializeAnalyzerReference(ObjectReader reader) + => ReadAnalyzerReferenceFrom(reader); } diff --git a/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs b/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs index 5d6516896f0af..6ccc3a847cbd5 100644 --- a/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs +++ b/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs @@ -44,23 +44,16 @@ private static bool TryGetAnalyzerImageReferenceFromGuid(Guid guid, [NotNullWhen return s_analyzerImageReferenceMap.TryGetKey(guid, out imageReference); } - public static Checksum CreateChecksum(MetadataReference reference, CancellationToken cancellationToken) + private static Checksum CreateChecksum(MetadataReference reference) { if (reference is PortableExecutableReference portable) - { - return CreatePortableExecutableReferenceChecksum(portable, cancellationToken); - } + return CreatePortableExecutableReferenceChecksum(portable); throw ExceptionUtilities.UnexpectedValue(reference.GetType()); } - private static bool IsAnalyzerReferenceWithShadowCopyLoader(AnalyzerFileReference reference) - => reference.AssemblyLoader is ShadowCopyAnalyzerAssemblyLoader; - - public static Checksum CreateChecksum(AnalyzerReference reference, CancellationToken cancellationToken) + protected virtual Checksum CreateChecksum(AnalyzerReference reference) { - cancellationToken.ThrowIfCancellationRequested(); - using var stream = SerializableBytes.CreateWritableStream(); using (var writer = new ObjectWriter(stream, leaveOpen: true)) @@ -69,7 +62,7 @@ public static Checksum CreateChecksum(AnalyzerReference reference, CancellationT { case AnalyzerFileReference file: writer.WriteString(file.FullPath); - writer.WriteBoolean(IsAnalyzerReferenceWithShadowCopyLoader(file)); + writer.WriteGuid(TryGetAnalyzerFileReferenceMvid(file)); break; case AnalyzerImageReference analyzerImageReference: @@ -86,45 +79,59 @@ public static Checksum CreateChecksum(AnalyzerReference reference, CancellationT return Checksum.Create(stream); } - public virtual void WriteMetadataReferenceTo(MetadataReference reference, ObjectWriter writer, CancellationToken cancellationToken) + protected virtual void WriteMetadataReferenceTo(MetadataReference reference, ObjectWriter writer) { if (reference is PortableExecutableReference portable) { if (portable is ISupportTemporaryStorage { StorageHandles: { Count: > 0 } handles } && - TryWritePortableExecutableReferenceBackedByTemporaryStorageTo( - portable, handles, writer, cancellationToken)) + TryWritePortableExecutableReferenceBackedByTemporaryStorageTo(portable, handles, writer)) { return; } - WritePortableExecutableReferenceTo(portable, writer, cancellationToken); + WritePortableExecutableReferenceTo(portable, writer); return; } throw ExceptionUtilities.UnexpectedValue(reference.GetType()); } - public virtual MetadataReference ReadMetadataReferenceFrom(ObjectReader reader, CancellationToken cancellationToken) + protected virtual MetadataReference ReadMetadataReferenceFrom(ObjectReader reader) { var type = reader.ReadString(); if (type == nameof(PortableExecutableReference)) - { - return ReadPortableExecutableReferenceFrom(reader, cancellationToken); - } + return ReadPortableExecutableReferenceFrom(reader); throw ExceptionUtilities.UnexpectedValue(type); } - public virtual void WriteAnalyzerReferenceTo(AnalyzerReference reference, ObjectWriter writer, CancellationToken cancellationToken) + protected virtual void WriteAnalyzerReferenceTo(AnalyzerReference reference, ObjectWriter writer) { - cancellationToken.ThrowIfCancellationRequested(); - switch (reference) { case AnalyzerFileReference file: writer.WriteString(nameof(AnalyzerFileReference)); writer.WriteString(file.FullPath); - writer.WriteBoolean(IsAnalyzerReferenceWithShadowCopyLoader(file)); + + // Note: it is intentional that we are not writing the MVID of the analyzer file reference over (even + // though we mixed it into the checksum). We don't actually need the data on the other side as it will + // be read out from the file itself. So the flow is as follows when an analyzer-file-reference changes: + // + // 1. Change to file happens on disk and is detected by the host, which will reload the reference within it. + // 2. When producing the checksum for the project, this analyzer file reference will not be found in the + // ChecksumCache, causing it to be recomputed (in `Checksum CreateChecksum(AnalyzerReference + // reference, CancellationToken cancellationToken)`. + // 3. The checksum will be computed based on the file path and the MVID of the file. + // 4. This will now cause a diff between the host and OOP. + // 5. When OOP syncs with the host, it will create a fresh AnalyzerFileReference pointing to the right + // path, and specifying it wants to use the shadow copy loader. The workspace snapshot will be + // updated to use this new reference. Note: this is guaranteed, as `SolutionCompilationState + // WithProjectAnalyzerReferences(...)` uses reference-equality to determine if the analyzer is + // different, always picking up the new instances. + // 6. When we actually need to load analyzers/generators in OOP it will then defer to the + // ShadowCopyAnalyzerAssemblyLoader. This loader will *itself* then use the MVID of the file + // reference at the requested path to shadow copy to a new location specific to that mvid, ensuring + // that its data can be cleanly loaded in isolation from any prior version. break; case AnalyzerImageReference analyzerImageReference: @@ -138,57 +145,54 @@ public virtual void WriteAnalyzerReferenceTo(AnalyzerReference reference, Object } } - public virtual AnalyzerReference ReadAnalyzerReferenceFrom(ObjectReader reader, CancellationToken cancellationToken) + protected virtual AnalyzerReference ReadAnalyzerReferenceFrom(ObjectReader reader) { - cancellationToken.ThrowIfCancellationRequested(); - - var type = reader.ReadString(); - switch (type) + switch (reader.ReadString()) { case nameof(AnalyzerFileReference): var fullPath = reader.ReadRequiredString(); - var shadowCopy = reader.ReadBoolean(); - return new AnalyzerFileReference(fullPath, _analyzerLoaderProvider.GetLoader(shadowCopy)); + return new AnalyzerFileReference(fullPath, _analyzerLoaderProvider.SharedShadowCopyLoader); case nameof(AnalyzerImageReference): var guid = reader.ReadGuid(); Contract.ThrowIfFalse(TryGetAnalyzerImageReferenceFromGuid(guid, out var analyzerImageReference)); return analyzerImageReference; - } - throw ExceptionUtilities.UnexpectedValue(type); + case var type: + throw ExceptionUtilities.UnexpectedValue(type); + } } protected static void WritePortableExecutableReferenceHeaderTo( - PortableExecutableReference reference, SerializationKinds kind, ObjectWriter writer, CancellationToken cancellationToken) + PortableExecutableReference reference, SerializationKinds kind, ObjectWriter writer) { writer.WriteString(nameof(PortableExecutableReference)); writer.WriteInt32((int)kind); - WritePortableExecutableReferencePropertiesTo(reference, writer, cancellationToken); + WritePortableExecutableReferencePropertiesTo(reference, writer); } - private static void WritePortableExecutableReferencePropertiesTo(PortableExecutableReference reference, ObjectWriter writer, CancellationToken cancellationToken) + private static void WritePortableExecutableReferencePropertiesTo(PortableExecutableReference reference, ObjectWriter writer) { - WriteTo(reference.Properties, writer, cancellationToken); + WriteTo(reference.Properties, writer); writer.WriteString(reference.FilePath); } - private static Checksum CreatePortableExecutableReferenceChecksum(PortableExecutableReference reference, CancellationToken cancellationToken) + private static Checksum CreatePortableExecutableReferenceChecksum(PortableExecutableReference reference) { using var stream = SerializableBytes.CreateWritableStream(); using (var writer = new ObjectWriter(stream, leaveOpen: true)) { - WritePortableExecutableReferencePropertiesTo(reference, writer, cancellationToken); - WriteMvidsTo(TryGetMetadata(reference), writer, cancellationToken); + WritePortableExecutableReferencePropertiesTo(reference, writer); + WriteMvidsTo(TryGetMetadata(reference), writer); } stream.Position = 0; return Checksum.Create(stream); } - private static void WriteMvidsTo(Metadata? metadata, ObjectWriter writer, CancellationToken cancellationToken) + private static void WriteMvidsTo(Metadata? metadata, ObjectWriter writer) { if (metadata == null) { @@ -206,18 +210,14 @@ private static void WriteMvidsTo(Metadata? metadata, ObjectWriter writer, Cancel } writer.WriteInt32((int)assemblyMetadata.Kind); - writer.WriteInt32(modules.Length); - foreach (var module in modules) - { - WriteMvidTo(module, writer, cancellationToken); - } + WriteMvidTo(module, writer); return; } - WriteMvidTo((ModuleMetadata)metadata, writer, cancellationToken); + WriteMvidTo((ModuleMetadata)metadata, writer); } private static bool TryGetModules(AssemblyMetadata assemblyMetadata, out ImmutableArray modules) @@ -237,10 +237,8 @@ IOException or } } - private static void WriteMvidTo(ModuleMetadata metadata, ObjectWriter writer, CancellationToken cancellationToken) + private static void WriteMvidTo(ModuleMetadata metadata, ObjectWriter writer) { - cancellationToken.ThrowIfCancellationRequested(); - writer.WriteInt32((int)metadata.Kind); writer.WriteGuid(GetMetadataGuid(metadata)); } @@ -254,31 +252,30 @@ private static Guid GetMetadataGuid(ModuleMetadata metadata) } private static void WritePortableExecutableReferenceTo( - PortableExecutableReference reference, ObjectWriter writer, CancellationToken cancellationToken) + PortableExecutableReference reference, ObjectWriter writer) { - WritePortableExecutableReferenceHeaderTo(reference, SerializationKinds.Bits, writer, cancellationToken); - - WriteTo(TryGetMetadata(reference), writer, cancellationToken); + WritePortableExecutableReferenceHeaderTo(reference, SerializationKinds.Bits, writer); + WriteTo(TryGetMetadata(reference), writer); // TODO: what I should do with documentation provider? it is not exposed outside } - private PortableExecutableReference ReadPortableExecutableReferenceFrom(ObjectReader reader, CancellationToken cancellationToken) + private PortableExecutableReference ReadPortableExecutableReferenceFrom(ObjectReader reader) { var kind = (SerializationKinds)reader.ReadInt32(); Contract.ThrowIfFalse(kind is SerializationKinds.Bits or SerializationKinds.MemoryMapFile); - var properties = ReadMetadataReferencePropertiesFrom(reader, cancellationToken); + var properties = ReadMetadataReferencePropertiesFrom(reader); var filePath = reader.ReadString(); - if (TryReadMetadataFrom(reader, kind, cancellationToken) is not (var metadata, var storageHandles)) + if (TryReadMetadataFrom(reader, kind) is not (var metadata, var storageHandles)) { // TODO: deal with xml document provider properly // should we shadow copy xml doc comment? // image doesn't exist - return new MissingMetadataReference(properties, filePath, XmlDocumentationProvider.Default); + return new MissingMetadataReference(properties, filePath, DocumentationProvider.Default); } // for now, we will use IDocumentationProviderService to get DocumentationProvider for metadata @@ -291,23 +288,19 @@ private PortableExecutableReference ReadPortableExecutableReferenceFrom(ObjectRe var documentProvider = filePath != null && _documentationService != null ? _documentationService.GetDocumentationProvider(filePath) : XmlDocumentationProvider.Default; - return new SerializedMetadataReference( + return new SerializedPortableExecutableReference( properties, filePath, metadata, storageHandles, documentProvider); } - private static void WriteTo(MetadataReferenceProperties properties, ObjectWriter writer, CancellationToken cancellationToken) + private static void WriteTo(MetadataReferenceProperties properties, ObjectWriter writer) { - cancellationToken.ThrowIfCancellationRequested(); - writer.WriteInt32((int)properties.Kind); writer.WriteArray(properties.Aliases, static (w, a) => w.WriteString(a)); writer.WriteBoolean(properties.EmbedInteropTypes); } - private static MetadataReferenceProperties ReadMetadataReferencePropertiesFrom(ObjectReader reader, CancellationToken cancellationToken) + private static MetadataReferenceProperties ReadMetadataReferencePropertiesFrom(ObjectReader reader) { - cancellationToken.ThrowIfCancellationRequested(); - var kind = (MetadataImageKind)reader.ReadInt32(); var aliases = reader.ReadArray(static r => r.ReadRequiredString()); var embedInteropTypes = reader.ReadBoolean(); @@ -315,7 +308,7 @@ private static MetadataReferenceProperties ReadMetadataReferencePropertiesFrom(O return new MetadataReferenceProperties(kind, aliases, embedInteropTypes); } - private static void WriteTo(Metadata? metadata, ObjectWriter writer, CancellationToken cancellationToken) + private static void WriteTo(Metadata? metadata, ObjectWriter writer) { if (metadata == null) { @@ -334,29 +327,25 @@ private static void WriteTo(Metadata? metadata, ObjectWriter writer, Cancellatio } writer.WriteInt32((int)assemblyMetadata.Kind); - writer.WriteInt32(modules.Length); foreach (var module in modules) - { - WriteTo(module, writer, cancellationToken); - } + WriteTo(module, writer); return; } - WriteTo((ModuleMetadata)metadata, writer, cancellationToken); + WriteTo((ModuleMetadata)metadata, writer); } private static bool TryWritePortableExecutableReferenceBackedByTemporaryStorageTo( PortableExecutableReference reference, IReadOnlyList handles, - ObjectWriter writer, - CancellationToken cancellationToken) + ObjectWriter writer) { Contract.ThrowIfTrue(handles.Count == 0); - WritePortableExecutableReferenceHeaderTo(reference, SerializationKinds.MemoryMapFile, writer, cancellationToken); + WritePortableExecutableReferenceHeaderTo(reference, SerializationKinds.MemoryMapFile, writer); writer.WriteInt32((int)MetadataImageKind.Assembly); writer.WriteInt32(handles.Count); @@ -371,7 +360,7 @@ private static bool TryWritePortableExecutableReferenceBackedByTemporaryStorageT } private (Metadata metadata, ImmutableArray storageHandles)? TryReadMetadataFrom( - ObjectReader reader, SerializationKinds kind, CancellationToken cancellationToken) + ObjectReader reader, SerializationKinds kind) { var imageKind = reader.ReadInt32(); if (imageKind == MetadataFailed) @@ -393,7 +382,7 @@ private static bool TryWritePortableExecutableReferenceBackedByTemporaryStorageT metadataKind = (MetadataImageKind)reader.ReadInt32(); Contract.ThrowIfFalse(metadataKind == MetadataImageKind.Module); - var (metadata, storageHandle) = ReadModuleMetadataFrom(reader, kind, cancellationToken); + var (metadata, storageHandle) = ReadModuleMetadataFrom(reader, kind); allMetadata.Add(metadata); allHandles.Add(storageHandle); @@ -405,16 +394,14 @@ private static bool TryWritePortableExecutableReferenceBackedByTemporaryStorageT { Contract.ThrowIfFalse(metadataKind == MetadataImageKind.Module); - var moduleInfo = ReadModuleMetadataFrom(reader, kind, cancellationToken); + var moduleInfo = ReadModuleMetadataFrom(reader, kind); return (moduleInfo.metadata, [moduleInfo.storageHandle]); } } private (ModuleMetadata metadata, TemporaryStorageStreamHandle storageHandle) ReadModuleMetadataFrom( - ObjectReader reader, SerializationKinds kind, CancellationToken cancellationToken) + ObjectReader reader, SerializationKinds kind) { - cancellationToken.ThrowIfCancellationRequested(); - Contract.ThrowIfFalse(kind is SerializationKinds.Bits or SerializationKinds.MemoryMapFile); return kind == SerializationKinds.Bits @@ -435,10 +422,10 @@ private static bool TryWritePortableExecutableReferenceBackedByTemporaryStorageT // Host is sending us all the data as bytes. Take that and write that out to a memory mapped file on the // server side so that we can refer to this data uniformly. using var stream = SerializableBytes.CreateWritableStream(); - CopyByteArrayToStream(reader, stream, cancellationToken); + CopyByteArrayToStream(reader, stream); var length = stream.Length; - var storageHandle = _storageService.Value.WriteToTemporaryStorage(stream, cancellationToken); + var storageHandle = _storageService.Value.WriteToTemporaryStorage(stream); Contract.ThrowIfTrue(length != storageHandle.Identifier.Size); return ReadModuleMetadataFromStorage(storageHandle); } @@ -452,7 +439,7 @@ private static bool TryWritePortableExecutableReferenceBackedByTemporaryStorageT // // The ITemporaryStorageStreamHandle should have given us an UnmanagedMemoryStream // since this only runs on Windows for VS. - var unmanagedStream = (UnmanagedMemoryStream)storageHandle.ReadFromTemporaryStorage(cancellationToken); + var unmanagedStream = (UnmanagedMemoryStream)storageHandle.ReadFromTemporaryStorage(); Contract.ThrowIfFalse(storageHandle.Identifier.Size == unmanagedStream.Length); // For an unmanaged memory stream, ModuleMetadata can take ownership directly. Stream will be kept alive as @@ -467,26 +454,21 @@ private static bool TryWritePortableExecutableReferenceBackedByTemporaryStorageT } } - private static void CopyByteArrayToStream(ObjectReader reader, Stream stream, CancellationToken cancellationToken) + private static void CopyByteArrayToStream(ObjectReader reader, Stream stream) { - cancellationToken.ThrowIfCancellationRequested(); - // TODO: make reader be able to read byte[] chunk var content = reader.ReadByteArray(); stream.Write(content, 0, content.Length); } - private static void WriteTo(ModuleMetadata metadata, ObjectWriter writer, CancellationToken cancellationToken) + private static void WriteTo(ModuleMetadata metadata, ObjectWriter writer) { writer.WriteInt32((int)metadata.Kind); - - WriteTo(metadata.GetMetadataReader(), writer, cancellationToken); + WriteTo(metadata.GetMetadataReader(), writer); } - private static unsafe void WriteTo(MetadataReader reader, ObjectWriter writer, CancellationToken cancellationToken) + private static unsafe void WriteTo(MetadataReader reader, ObjectWriter writer) { - cancellationToken.ThrowIfCancellationRequested(); - writer.WriteSpan(new ReadOnlySpan(reader.MetadataPointer, reader.MetadataLength)); } @@ -504,13 +486,26 @@ private static void WriteUnresolvedAnalyzerReferenceTo(AnalyzerReference referen } catch { - // we have a reference but the file the reference is pointing to - // might not actually exist on disk. - // in that case, rather than crashing, we will handle it gracefully. + // We have a reference but the file the reference is pointing to might not actually exist on disk. In that + // case, rather than crashing, we will handle it gracefully. return null; } } + private static Guid TryGetAnalyzerFileReferenceMvid(AnalyzerFileReference file) + { + try + { + return AssemblyUtilities.ReadMvid(file.FullPath); + } + catch + { + // We have a reference but the file the reference is pointing to might not actually exist on disk. In that + // case, rather than crashing, we will handle it gracefully. + return Guid.Empty; + } + } + private sealed class MissingMetadataReference : PortableExecutableReference { private readonly DocumentationProvider _provider; diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/AnalyzerReferenceExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/AnalyzerReferenceExtensions.cs new file mode 100644 index 0000000000000..7d6bec82610ee --- /dev/null +++ b/src/Workspaces/Core/Portable/Shared/Extensions/AnalyzerReferenceExtensions.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.Diagnostics; + +namespace Microsoft.CodeAnalysis.Shared.Extensions; + +internal static class AnalyzerReferenceExtensions +{ + public static bool HasAnalyzersOrSourceGenerators(this AnalyzerReference analyzerFileReference, string language) + => !analyzerFileReference.GetAnalyzers(language).IsDefaultOrEmpty || + !analyzerFileReference.GetGenerators(language).IsDefaultOrEmpty; +} diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs index e947f678c5399..a27788c516f15 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs @@ -54,165 +54,6 @@ public static bool CompatibleSignatureToDelegate(this IMethodSymbol method, INam return true; } - 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 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 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; - } - public static bool? IsMoreSpecificThan(this IMethodSymbol method1, IMethodSymbol method2) { var p1 = method1.Parameters; diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/IParameterSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/IParameterSymbolExtensions.cs index 431849b2f8c0a..d56f340cb57e2 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/IParameterSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/IParameterSymbolExtensions.cs @@ -10,21 +10,6 @@ namespace Microsoft.CodeAnalysis.Shared.Extensions; internal static partial class IParameterSymbolExtensions { - 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); - } - public static IParameterSymbol WithAttributes(this IParameterSymbol parameter, ImmutableArray attributes) { return parameter.GetAttributes() == attributes @@ -39,13 +24,4 @@ public static IParameterSymbol WithAttributes(this IParameterSymbol parameter, I parameter.HasExplicitDefaultValue, parameter.HasExplicitDefaultValue ? parameter.ExplicitDefaultValue : null); } - - 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(); - } } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.cs index 81d5e4ae6b509..a27ff01a2706a 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.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.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; @@ -174,62 +172,6 @@ from member in baseType.GetMembers(constructedInterfaceMember.Name).OfType 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)); - } - - [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)); - } - public static bool CanBeEnumerated(this ITypeSymbol type) { // Type itself is IEnumerable/IEnumerable diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SourceTextExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SourceTextExtensions.cs index 1eef6e5b28e97..5ba3bca4346bd 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SourceTextExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SourceTextExtensions.cs @@ -214,14 +214,7 @@ private static void WriteChunksTo(SourceText sourceText, ObjectWriter writer, in var count = Math.Min(buffer.Length, length - offset); sourceText.CopyTo(offset, buffer, 0, count); - // In the case where the array is entirely full, we can pass that as is to the ObjectWriter. It already - // supports sending the array all the way through to the underlying stream without allocations. In the case - // where it's partially full, we pass in a span to the section that is filled. This will fast path on - // netcore, though will incur a copy to pooled memory on netfx. - if (count == buffer.Length) - writer.WriteCharArray(buffer); - else - writer.WriteSpan(buffer.AsSpan()[..count]); + writer.WriteCharArray(buffer, 0, count); offset += count; } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs index ecce1282f978b..991cd1db6866a 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs @@ -40,271 +40,6 @@ public static IMethodSymbol CreateBaseDelegatingConstructor( : factory.CreateArguments(constructor.Parameters)); } - public static ImmutableArray CreateMemberDelegatingConstructor( - this SyntaxGenerator factory, - 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( - 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; - } - - 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(); - } - - 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 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, - SemanticModel semanticModel, - IParameterSymbol parameter) - { - var condition = factory.CreateNullCheckExpression(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 CreateThrowArgumentNullExceptionStatement(this SyntaxGenerator factory, Compilation compilation, IParameterSymbol parameter) - => factory.ThrowStatement(CreateNewArgumentNullException(factory, compilation, parameter)); - - public static SyntaxNode CreateNullCheckExpression(this SyntaxGenerator factory, SemanticModel semanticModel, string identifierName) - { - var identifier = factory.IdentifierName(identifierName); - var nullExpr = factory.NullLiteralExpression(); - var condition = factory.SyntaxGeneratorInternal.SupportsPatterns(semanticModel.SyntaxTree.Options) - ? factory.SyntaxGeneratorInternal.IsPatternExpression(identifier, factory.SyntaxGeneratorInternal.ConstantPattern(nullExpr)) - : factory.ReferenceEqualsExpression(identifier, nullExpr); - return condition; - } - - public static ImmutableArray CreateAssignmentStatements( - this SyntaxGenerator factory, - 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( - semanticModel, parameter, fieldAccess, - addNullChecks, preferThrowExpression, - nullCheckStatements, assignStatements); - } - } - } - - return nullCheckStatements.ToImmutableAndFree().Concat(assignStatements.ToImmutableAndFree()); - } - - public static void AddAssignmentStatements( - this SyntaxGenerator factory, - 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 && factory.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(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 async Task OverridePropertyAsync( this SyntaxGenerator codeFactory, IPropertySymbol overriddenProperty, @@ -321,7 +56,7 @@ public static async Task OverridePropertyAsync( // Implement an abstract property by throwing not implemented in accessors. if (overriddenProperty.IsAbstract) { - var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); var statement = codeFactory.CreateThrowNotImplementedStatement(compilation); getBody = statement; @@ -510,7 +245,7 @@ private static async Task OverrideMethodAsync( // Abstract: Throw not implemented if (overriddenMethod.IsAbstract) { - var compilation = await newDocument.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + var compilation = await newDocument.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); var statement = codeFactory.CreateThrowNotImplementedStatement(compilation); return CodeGenerationSymbolFactory.CreateMethodSymbol( @@ -544,149 +279,4 @@ private static async Task OverrideMethodAsync( : [codeFactory.ReturnStatement(body)]); } } - - /// - /// 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); - } } diff --git a/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs b/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs index 6830aaa1854f2..732aa7f640968 100644 --- a/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs +++ b/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs @@ -16,6 +16,7 @@ internal static class FeatureAttribute public const string CodeDefinitionWindow = nameof(CodeDefinitionWindow); public const string CodeLens = nameof(CodeLens); public const string CodeModel = nameof(CodeModel); + public const string ColorScheme = nameof(ColorScheme); public const string CompletionSet = nameof(CompletionSet); public const string CopilotSuggestions = nameof(CopilotSuggestions); public const string DesignerAttributes = nameof(DesignerAttributes); diff --git a/src/Workspaces/Core/Portable/SourceGeneration/IRemoteSourceGenerationService.cs b/src/Workspaces/Core/Portable/SourceGeneration/IRemoteSourceGenerationService.cs index fffa94b324236..d0821c325762e 100644 --- a/src/Workspaces/Core/Portable/SourceGeneration/IRemoteSourceGenerationService.cs +++ b/src/Workspaces/Core/Portable/SourceGeneration/IRemoteSourceGenerationService.cs @@ -8,12 +8,13 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.SourceGeneration; [DataContract] -internal readonly record struct SourceGeneratedDocmentInfo( +internal readonly record struct SourceGeneratedDocumentInfo( [property: DataMember(Order = 0)] SourceGeneratedDocumentIdentity DocumentIdentity, [property: DataMember(Order = 1)] SourceGeneratedDocumentContentIdentity ContentIdentity, [property: DataMember(Order = 2)] DateTime GenerationDateTime); @@ -30,7 +31,7 @@ internal interface IRemoteSourceGenerationService /// Controls if the caller wants frozen source generator documents /// included in the result, or if only the most underlying generated documents (produced by the real compiler should be included. - ValueTask> GetSourceGeneratedDocumentInfoAsync( + ValueTask> GetSourceGeneratedDocumentInfoAsync( Checksum solutionChecksum, ProjectId projectId, bool withFrozenSourceGeneratedDocuments, CancellationToken cancellationToken); /// @@ -49,6 +50,20 @@ ValueTask> GetContentsAsync( /// ValueTask HasGeneratorsAsync( Checksum solutionChecksum, ProjectId projectId, ImmutableArray analyzerReferenceChecksums, string language, CancellationToken cancellationToken); + + /// + /// Returns the identities for all source generators found in the with equal to . + /// + ValueTask> GetSourceGeneratorIdentitiesAsync( + Checksum solutionChecksum, ProjectId projectId, string analyzerReferenceFullPath, CancellationToken cancellationToken); + + /// + /// Returns whether or not the the with + /// equal to has any analyzers or source generators. + /// + ValueTask HasAnalyzersOrSourceGeneratorsAsync( + Checksum solutionChecksum, ProjectId projectId, string analyzerReferenceFullPath, CancellationToken cancellationToken); } /// diff --git a/src/Workspaces/Core/Portable/Storage/SQLite/v2/Interop/SqlStatement.cs b/src/Workspaces/Core/Portable/Storage/SQLite/v2/Interop/SqlStatement.cs index 3658e0dd9a462..3a77291393a0d 100644 --- a/src/Workspaces/Core/Portable/Storage/SQLite/v2/Interop/SqlStatement.cs +++ b/src/Workspaces/Core/Portable/Storage/SQLite/v2/Interop/SqlStatement.cs @@ -80,7 +80,7 @@ internal void BindStringParameter(int parameterIndex, string value) if (utf8ByteCount <= OptimizedLengthThreshold) { Span bytes = stackalloc byte[utf8ByteCount]; -#if NETCOREAPP +#if NET Contract.ThrowIfFalse(Encoding.UTF8.GetBytes(value.AsSpan(), bytes) == utf8ByteCount); #else unsafe diff --git a/src/Workspaces/Core/Portable/SymbolSearch/SymbolSearchOptions.cs b/src/Workspaces/Core/Portable/SymbolSearch/SymbolSearchOptions.cs deleted file mode 100644 index 2ea25038f4b27..0000000000000 --- a/src/Workspaces/Core/Portable/SymbolSearch/SymbolSearchOptions.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.Runtime.Serialization; - -namespace Microsoft.CodeAnalysis.SymbolSearch; - -[DataContract] -internal readonly record struct SymbolSearchOptions -{ - [DataMember] public bool SearchReferenceAssemblies { get; init; } = true; - [DataMember] public bool SearchNuGetPackages { get; init; } = true; - - // required to make sure new SymbolSearchOptions() runs property initializers - public SymbolSearchOptions() - { - } - - public static readonly SymbolSearchOptions Default = new(); -} diff --git a/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.TemporaryStorageStreamHandle.cs b/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.TemporaryStorageStreamHandle.cs index 5aff9e6a84a44..95f2e0c2147d7 100644 --- a/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.TemporaryStorageStreamHandle.cs +++ b/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.TemporaryStorageStreamHandle.cs @@ -18,12 +18,10 @@ public sealed class TemporaryStorageStreamHandle( { public TemporaryStorageIdentifier Identifier => identifier; - public Stream ReadFromTemporaryStorage(CancellationToken cancellationToken) + public Stream ReadFromTemporaryStorage() { - using (Logger.LogBlock(FunctionId.TemporaryStorageServiceFactory_ReadStream, cancellationToken)) + using (Logger.LogBlock(FunctionId.TemporaryStorageServiceFactory_ReadStream, CancellationToken.None)) { - cancellationToken.ThrowIfCancellationRequested(); - var info = new MemoryMappedInfo(memoryMappedFile, Identifier.Name, Identifier.Offset, Identifier.Size); return info.CreateReadableStream(); } diff --git a/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.cs b/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.cs index 56a205c39481b..adf3210139dbd 100644 --- a/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.cs +++ b/src/Workspaces/Core/Portable/TemporaryStorage/TemporaryStorageService.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.Host; /// /// Temporarily stores text and streams in memory mapped files. /// -#if NETCOREAPP +#if NET [SupportedOSPlatform("windows")] #endif internal sealed partial class TemporaryStorageService : ITemporaryStorageServiceInternal @@ -137,9 +137,9 @@ public async Task WriteToTemporaryStorageAsync(Sourc } ITemporaryStorageStreamHandle ITemporaryStorageServiceInternal.WriteToTemporaryStorage(Stream stream, CancellationToken cancellationToken) - => WriteToTemporaryStorage(stream, cancellationToken); + => WriteToTemporaryStorage(stream); - public TemporaryStorageStreamHandle WriteToTemporaryStorage(Stream stream, CancellationToken cancellationToken) + public TemporaryStorageStreamHandle WriteToTemporaryStorage(Stream stream) { stream.Position = 0; var memoryMappedInfo = WriteToMemoryMappedFile(); @@ -148,7 +148,7 @@ public TemporaryStorageStreamHandle WriteToTemporaryStorage(Stream stream, Cance MemoryMappedInfo WriteToMemoryMappedFile() { - using (Logger.LogBlock(FunctionId.TemporaryStorageServiceFactory_WriteStream, cancellationToken)) + using (Logger.LogBlock(FunctionId.TemporaryStorageServiceFactory_WriteStream, CancellationToken.None)) { var size = stream.Length; var memoryMappedInfo = this.CreateTemporaryStorage(size); diff --git a/src/Workspaces/Core/Portable/TemporaryStorage/TrivialTemporaryStorageService.cs b/src/Workspaces/Core/Portable/TemporaryStorage/TrivialTemporaryStorageService.cs index 834179fc20725..61dade9c396f8 100644 --- a/src/Workspaces/Core/Portable/TemporaryStorage/TrivialTemporaryStorageService.cs +++ b/src/Workspaces/Core/Portable/TemporaryStorage/TrivialTemporaryStorageService.cs @@ -48,7 +48,7 @@ public StreamStorage(MemoryStream stream) Identifier = new TemporaryStorageIdentifier(Guid.NewGuid().ToString(), 0, _stream.Length); } - public Stream ReadFromTemporaryStorage(CancellationToken cancellationToken) + public Stream ReadFromTemporaryStorage() { // Return a read-only view of the underlying buffer to prevent users from overwriting or directly // disposing the backing storage. diff --git a/src/Workspaces/Core/Portable/Utilities/TaskQueue.cs b/src/Workspaces/Core/Portable/Utilities/TaskQueue.cs index b115e7fd06b3f..a8b5380f6bae6 100644 --- a/src/Workspaces/Core/Portable/Utilities/TaskQueue.cs +++ b/src/Workspaces/Core/Portable/Utilities/TaskQueue.cs @@ -18,7 +18,6 @@ internal sealed class TaskQueue public TaskScheduler Scheduler { get; } private readonly object _gate = new(); - private Task _latestTask; public TaskQueue(IAsynchronousOperationListener operationListener, TaskScheduler taskScheduler) { @@ -27,10 +26,10 @@ public TaskQueue(IAsynchronousOperationListener operationListener, TaskScheduler Listener = operationListener; Scheduler = taskScheduler; - _latestTask = Task.CompletedTask; + LastScheduledTask = Task.CompletedTask; } - public Task LastScheduledTask => _latestTask; + public Task LastScheduledTask { get; private set; } private IAsyncToken BeginOperation(string taskName) => Listener.BeginAsyncOperation(taskName); @@ -74,8 +73,8 @@ private Task ScheduleTaskInProgress(Action operation, CancellationToken cancella { lock (_gate) { - var task = _latestTask.SafeContinueWith(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); - _latestTask = task; + var task = LastScheduledTask.SafeContinueWith(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); + LastScheduledTask = task; return task; } } @@ -86,8 +85,8 @@ private Task ScheduleTaskInProgress(Func operation, CancellationToken c { lock (_gate) { - var task = _latestTask.SafeContinueWith(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); - _latestTask = task; + var task = LastScheduledTask.SafeContinueWith(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); + LastScheduledTask = task; return task; } } @@ -98,8 +97,8 @@ private Task ScheduleTaskInProgress(Func operation, CancellationToken canc { lock (_gate) { - var task = _latestTask.SafeContinueWithFromAsync(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); - _latestTask = task; + var task = LastScheduledTask.SafeContinueWithFromAsync(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); + LastScheduledTask = task; return task; } } @@ -110,8 +109,8 @@ private Task ScheduleTaskInProgress(Func> operation, CancellationT { lock (_gate) { - var task = _latestTask.SafeContinueWithFromAsync(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); - _latestTask = task; + var task = LastScheduledTask.SafeContinueWithFromAsync(_ => operation(), cancellationToken, TaskContinuationOptions.None, Scheduler); + LastScheduledTask = task; return task; } } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/Extensions.cs b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/Extensions.cs index 4d1cc382ae919..93159ed29e049 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/Extensions.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/Extensions.cs @@ -14,17 +14,17 @@ public static bool CanApplyChange([NotNullWhen(returnValue: true)] this TextDocu => document?.State.CanApplyChange() ?? false; public static bool CanApplyChange([NotNullWhen(returnValue: true)] this TextDocumentState? document) - => document?.Services.GetService()?.CanApplyChange ?? false; + => document?.DocumentServiceProvider.GetService()?.CanApplyChange ?? false; public static bool SupportsDiagnostics([NotNullWhen(returnValue: true)] this TextDocument? document) => document?.State.SupportsDiagnostics() ?? false; public static bool SupportsDiagnostics([NotNullWhen(returnValue: true)] this TextDocumentState? document) - => document?.Services.GetService()?.SupportDiagnostics ?? false; + => document?.DocumentServiceProvider.GetService()?.SupportDiagnostics ?? false; public static bool IsRazorDocument(this TextDocument document) => IsRazorDocument(document.State); public static bool IsRazorDocument(this TextDocumentState documentState) - => documentState.Services.GetService()?.DiagnosticsLspClientName == RazorCSharpLspClientName; + => documentState.DocumentServiceProvider.GetService()?.DiagnosticsLspClientName == RazorCSharpLspClientName; } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/HostLanguageServices.cs b/src/Workspaces/Core/Portable/Workspace/Host/HostLanguageServices.cs index 4ab944e886d58..99159021f2dff 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/HostLanguageServices.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/HostLanguageServices.cs @@ -3,13 +3,23 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.Host; /// -/// Per language services provided by the host environment. +/// Per-language services provided by the host environment. /// -public abstract class HostLanguageServices +/// +/// Language services which implement are considered ownable, in which case the +/// owner is responsible for disposing of owned instances when they are no longer in use. The ownership rules are +/// described in detail for . Instances of have +/// the same ownership rules as , and instances of +/// have the same ownership rules as +/// . +/// +public abstract class HostLanguageServices : IDisposable { /// /// The that originated this language service. @@ -40,6 +50,11 @@ protected HostLanguageServices() /// public abstract TLanguageService? GetService() where TLanguageService : ILanguageService; + [SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Derived types are not allowed to include a finalizer for this pattern.")] + public virtual void Dispose() + { + } + /// /// Gets a language specific service provided by the host identified by the service type. /// If the host does not provide the service, this method returns throws . diff --git a/src/Workspaces/Core/Portable/Workspace/Host/HostWorkspaceServices.cs b/src/Workspaces/Core/Portable/Workspace/Host/HostWorkspaceServices.cs index 8b3cd2bc20acb..0e360d99f30eb 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/HostWorkspaceServices.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/HostWorkspaceServices.cs @@ -5,6 +5,8 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Host; @@ -12,7 +14,35 @@ namespace Microsoft.CodeAnalysis.Host; /// /// Per workspace services provided by the host environment. /// -public abstract class HostWorkspaceServices +/// +/// Workspace services which implement are considered ownable, in which case the +/// owner is responsible for disposing of owned instances when they are no longer in use. When +/// or instances are provided directly to the +/// , the owner of the instances is the type or container (e.g. a MEF export +/// provider) which created the instances. For the specific case of ownable workspace services created by a factory +/// (i.e. instances returned by ), the +/// is considered the owner of the resulting instance and is expected to be disposed during the call to +/// . +/// +/// Summary of lifetime rules +/// +/// +/// +/// instance constructed externally (e.g. MEF): Owned by the +/// external source, and will not be automatically disposed when is disposed. +/// +/// +/// instance constructed externally (e.g. MEF): Owned by +/// the external source, and will not be automatically disposed when is disposed. +/// +/// +/// instance constructed by within +/// the context of : Owned by , and +/// will be automatically disposed when is disposed. +/// +/// +/// +public abstract class HostWorkspaceServices : IDisposable { /// /// The host services this workspace services originated from. @@ -40,6 +70,11 @@ protected HostWorkspaceServices() #pragma warning restore } + [SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Derived types are not allowed to include a finalizer for this pattern.")] + public virtual void Dispose() + { + } + /// /// Gets a workspace specific service provided by the host identified by the service type. /// If the host does not provide the service, this method throws . diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs index f650fae7dd782..3fea95eb30918 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/Metadata/IAnalyzerAssemblyLoaderProvider.cs @@ -2,9 +2,50 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.IO; +using Microsoft.CodeAnalysis.Host.Mef; + namespace Microsoft.CodeAnalysis.Host; internal interface IAnalyzerAssemblyLoaderProvider : IWorkspaceService { - IAnalyzerAssemblyLoader GetLoader(bool shadowCopy); + IAnalyzerAssemblyLoaderInternal SharedShadowCopyLoader { get; } } + +/// +/// Abstract implementation of an analyzer assembly loader that can be used by VS/VSCode to provide a with an appropriate path. +/// +internal abstract class AbstractAnalyzerAssemblyLoaderProvider : IAnalyzerAssemblyLoaderProvider +{ + private readonly ImmutableArray _externalResolvers; + private readonly Lazy _shadowCopyLoader; + + public AbstractAnalyzerAssemblyLoaderProvider(IEnumerable externalResolvers) + { + _externalResolvers = externalResolvers.ToImmutableArray(); + _shadowCopyLoader = new(CreateShadowCopyLoader); + } + + public IAnalyzerAssemblyLoaderInternal SharedShadowCopyLoader + => _shadowCopyLoader.Value; + + private IAnalyzerAssemblyLoaderInternal CreateShadowCopyLoader() + => this.WrapLoader(DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader( + Path.Combine(Path.GetTempPath(), nameof(Roslyn), "AnalyzerAssemblyLoader"), + _externalResolvers)); + + protected virtual IAnalyzerAssemblyLoaderInternal WrapLoader(IAnalyzerAssemblyLoaderInternal loader) + => loader; +} + +[ExportWorkspaceService(typeof(IAnalyzerAssemblyLoaderProvider)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class DefaultAnalyzerAssemblyLoaderProvider( + [ImportMany] IEnumerable externalResolvers) + : AbstractAnalyzerAssemblyLoaderProvider(externalResolvers); diff --git a/src/Workspaces/Core/Portable/Workspace/Host/SyntaxTreeFactory/AbstractSyntaxTreeFactoryService.cs b/src/Workspaces/Core/Portable/Workspace/Host/SyntaxTreeFactory/AbstractSyntaxTreeFactoryService.cs index b5a0c1f372766..94c103435fb2b 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/SyntaxTreeFactory/AbstractSyntaxTreeFactoryService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/SyntaxTreeFactory/AbstractSyntaxTreeFactoryService.cs @@ -17,6 +17,6 @@ internal abstract partial class AbstractSyntaxTreeFactoryService : ISyntaxTreeFa public abstract ParseOptions GetDefaultParseOptionsWithLatestLanguageVersion(); public abstract bool OptionsDifferOnlyByPreprocessorDirectives(ParseOptions options1, ParseOptions options2); public abstract ParseOptions TryParsePdbParseOptions(IReadOnlyDictionary metadata); - public abstract SyntaxTree CreateSyntaxTree(string filePath, ParseOptions options, Encoding encoding, SourceHashAlgorithm checksumAlgorithm, SyntaxNode root); + public abstract SyntaxTree CreateSyntaxTree(string filePath, ParseOptions options, SourceText text, Encoding encoding, SourceHashAlgorithm checksumAlgorithm, SyntaxNode root); public abstract SyntaxTree ParseSyntaxTree(string filePath, ParseOptions options, SourceText text, CancellationToken cancellationToken); } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/SyntaxTreeFactory/ISyntaxTreeFactoryService.cs b/src/Workspaces/Core/Portable/Workspace/Host/SyntaxTreeFactory/ISyntaxTreeFactoryService.cs index 3d1ffc15536aa..95ddecf9c0fe9 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/SyntaxTreeFactory/ISyntaxTreeFactoryService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/SyntaxTreeFactory/ISyntaxTreeFactoryService.cs @@ -26,8 +26,8 @@ internal interface ISyntaxTreeFactoryService : ILanguageService /// bool OptionsDifferOnlyByPreprocessorDirectives(ParseOptions options1, ParseOptions options2); - // new tree from root node - SyntaxTree CreateSyntaxTree(string? filePath, ParseOptions options, Encoding? encoding, SourceHashAlgorithm checksumAlgorithm, SyntaxNode root); + // new tree from root node and optional text + SyntaxTree CreateSyntaxTree(string? filePath, ParseOptions options, SourceText? text, Encoding? encoding, SourceHashAlgorithm checksumAlgorithm, SyntaxNode root); // new tree from text SyntaxTree ParseSyntaxTree(string? filePath, ParseOptions options, SourceText text, CancellationToken cancellationToken); diff --git a/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/ITemporaryStorageStreamHandle.cs b/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/ITemporaryStorageStreamHandle.cs index 418a8a7fe50cf..2a237a6fd1a47 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/ITemporaryStorageStreamHandle.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/ITemporaryStorageStreamHandle.cs @@ -22,5 +22,5 @@ internal interface ITemporaryStorageStreamHandle /// Reads the data indicated to by this handle into a stream. This stream can be created in a different process /// than the one that wrote the data originally. /// - Stream ReadFromTemporaryStorage(CancellationToken cancellationToken); + Stream ReadFromTemporaryStorage(); } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/LegacyTemporaryStorageService.cs b/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/LegacyTemporaryStorageService.cs index 9a640e04793a0..be4762ca42833 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/LegacyTemporaryStorageService.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/TemporaryStorage/LegacyTemporaryStorageService.cs @@ -69,7 +69,7 @@ public void WriteStream(Stream stream, CancellationToken cancellationToken = def public async Task WriteStreamAsync(Stream stream, CancellationToken cancellationToken = default) { var newStream = new MemoryStream(); -#if NETCOREAPP +#if NET await stream.CopyToAsync(newStream, cancellationToken).ConfigureAwait(false); # else await stream.CopyToAsync(newStream).ConfigureAwait(false); diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/FileWatchedPortableExecutableReferenceFactory.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/FileWatchedPortableExecutableReferenceFactory.cs index 90592e2f746f1..3cc09158ef1e1 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/FileWatchedPortableExecutableReferenceFactory.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/FileWatchedPortableExecutableReferenceFactory.cs @@ -4,60 +4,82 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; -using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Collections; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ProjectSystem; -internal sealed class FileWatchedPortableExecutableReferenceFactory +internal sealed class FileWatchedReferenceFactory + where TReference : class { private readonly object _gate = new(); /// - /// A file change context used to watch metadata references. This is lazy to avoid creating this immediately during our LSP process startup, when we - /// don't yet know the LSP client's capabilities. + /// A file change context used to watch metadata references. This is lazy to avoid creating this immediately during + /// our LSP process startup, when we don't yet know the LSP client's capabilities. /// private readonly Lazy _fileReferenceChangeContext; /// - /// File watching tokens from that are watching metadata references. These are only created once we are actually applying a batch because - /// we don't determine until the batch is applied if the file reference will actually be a file reference or it'll be a converted project reference. + /// File watching tokens from that are watching metadata references. These + /// are only created once we are actually applying a batch because we don't determine until the batch is applied if + /// the file reference will actually be a file reference or it'll be a converted project reference. /// - private readonly Dictionary _metadataReferenceFileWatchingTokens = []; + private readonly Dictionary _referenceFileWatchingTokens = []; /// - /// Stores the caller for a previous disposal of a reference produced by this class, to track down a double-dispose issue. + /// Stores the caller for a previous disposal of a reference produced by this class, to track down a double-dispose + /// issue. /// /// /// This can be removed once https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1843611 is fixed. /// - private readonly ConditionalWeakTable _previousDisposalLocations = new(); + private readonly ConditionalWeakTable _previousDisposalLocations = new(); - /// - /// s for in-flight refreshing of metadata references. When we see a file change, we wait a bit before trying to actually - /// update the workspace. We need cancellation tokens for those so we can cancel them either when a flurry of events come in (so we only do the delay after the last - /// modification), or when we know the project is going away entirely. - /// - private readonly Dictionary _metadataReferenceRefreshCancellationTokenSources = []; + private readonly AsyncBatchingWorkQueue _workQueue; + + private readonly Func _callback; - public FileWatchedPortableExecutableReferenceFactory( - IFileChangeWatcher fileChangeWatcher) + public FileWatchedReferenceFactory( + IFileChangeWatcher fileChangeWatcher, + IAsynchronousOperationListener asyncListener, + Func callback, + CancellationToken cancellationToken) { + _callback = callback; + _workQueue = new AsyncBatchingWorkQueue( + TimeSpan.FromSeconds(5), + ProcessWorkAsync, + // Dedupe notifications for the same file path + EqualityComparer.Default, + asyncListener, + cancellationToken); + _fileReferenceChangeContext = new Lazy(() => { - var referenceDirectories = new HashSet(); + var fileReferenceChangeContext = fileChangeWatcher.CreateContext(GetAdditionalWatchedDirectories()); + fileReferenceChangeContext.FileChanged += (s, e) => _workQueue.AddWork(e); + return fileReferenceChangeContext; + }); + + static ImmutableArray GetAdditionalWatchedDirectories() + { + using var _ = PooledHashSet.GetInstance(out var referenceDirectories); - // On each platform, there is a place that reference assemblies for the framework are installed. These are rarely going to be changed - // but are the most common places that we're going to create file watches. Rather than either creating a huge number of file watchers - // for every single file, or eventually realizing we should just watch these directories, we just create the single directory watchers now. - // We'll collect this from two places: constructing it from known environment variables, and also for the defaults where those environment - // variables would usually point, as a fallback. + // On each platform, there is a place that reference assemblies for the framework are installed. These are + // rarely going to be changed but are the most common places that we're going to create file watches. Rather + // than either creating a huge number of file watchers for every single file, or eventually realizing we + // should just watch these directories, we just create the single directory watchers now. We'll collect this + // from two places: constructing it from known environment variables, and also for the defaults where those + // environment variables would usually point, as a fallback. if (Environment.GetEnvironmentVariable("DOTNET_ROOT") is string dotnetRoot && !string.IsNullOrEmpty(dotnetRoot)) { @@ -79,56 +101,59 @@ public FileWatchedPortableExecutableReferenceFactory( referenceDirectories.Add("/usr/local/share/dotnet/packs"); } - // Also watch the NuGet restore path; we don't do this (yet) on Windows due to potential concerns about whether - // this creates additional overhead responding to changes during a restore. - // TODO: remove this condition + // Also watch the NuGet restore path; we don't do this (yet) on Windows due to potential concerns about + // whether this creates additional overhead responding to changes during a restore. TODO: remove this + // condition if (!PlatformInformation.IsWindows) { referenceDirectories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages")); } - var directoriesToWatch = referenceDirectories.Select(static d => new WatchedDirectory(d, ".dll")).ToArray(); - var fileReferenceChangeContext = fileChangeWatcher.CreateContext(directoriesToWatch); - fileReferenceChangeContext.FileChanged += FileReferenceChangeContext_FileChanged; - return fileReferenceChangeContext; - }); + return referenceDirectories.SelectAsArray(static d => new WatchedDirectory(d, ".dll")); + } } - public event EventHandler? ReferenceChanged; - /// - /// Starts watching a particular PortableExecutableReference for changes to the file. - /// If this is already being watched , the reference count will be incremented. - /// This is *not* safe to attempt to call multiple times for the same project and reference (e.g. in applying workspace updates) + /// Starts watching a particular for changes to the file. If this is already being + /// watched , the reference count will be incremented. This is *not* safe to attempt to call multiple times for the + /// same project and reference (e.g. in applying workspace updates) /// - public void StartWatchingReference(PortableExecutableReference reference, string fullFilePath) + public void StartWatchingReference(string fullFilePath) { lock (_gate) { - var (token, count) = _metadataReferenceFileWatchingTokens.GetOrAdd(reference, _ => + var (token, count) = _referenceFileWatchingTokens.GetOrAdd(fullFilePath, _ => { var fileToken = _fileReferenceChangeContext.Value.EnqueueWatchingFile(fullFilePath); return (fileToken, RefCount: 0); }); - _metadataReferenceFileWatchingTokens[reference] = (token, RefCount: count + 1); + + _referenceFileWatchingTokens[fullFilePath] = (token, RefCount: count + 1); } } /// - /// Decrements the reference count for the given PortableExecutableReference. - /// When the reference count reaches 0, the file watcher will be stopped. - /// This is *not* safe to attempt to call multiple times for the same project and reference (e.g. in applying workspace updates) + /// Decrements the reference count for the given . When the reference count reaches + /// 0, the file watcher will be stopped. This is *not* safe to attempt to call multiple times for the same project + /// and reference (e.g. in applying workspace updates) /// - public void StopWatchingReference(PortableExecutableReference reference, [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = 0) + public void StopWatchingReference(string fullFilePath, TReference? referenceToTrack, [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = 0) { lock (_gate) { var disposalLocation = callerFilePath + ", line " + callerLineNumber; - if (!_metadataReferenceFileWatchingTokens.TryGetValue(reference, out var watchedFileReference)) + if (!_referenceFileWatchingTokens.TryGetValue(fullFilePath, out var watchedFileReference)) { - // We're attempting to stop watching a file that we never started watching. This is a bug. - var existingDisposalStackTrace = _previousDisposalLocations.TryGetValue(reference, out var previousDisposalLocation); - throw new ArgumentException("The reference was already disposed at " + previousDisposalLocation); + if (referenceToTrack != null) + { + // We're attempting to stop watching a file that we never started watching. This is a bug. + var existingDisposalStackTrace = _previousDisposalLocations.TryGetValue(referenceToTrack, out var previousDisposalLocation); + throw new ArgumentException("The reference was already disposed at " + previousDisposalLocation); + } + else + { + throw new ArgumentException("Attempting to stop watching a file that we never started watching. This is a bug."); + } } var newRefCount = watchedFileReference.RefCount - 1; @@ -137,64 +162,36 @@ public void StopWatchingReference(PortableExecutableReference reference, [Caller { // No one else is watching this file, so stop watching it and remove from our map. watchedFileReference.Token.Dispose(); - _metadataReferenceFileWatchingTokens.Remove(reference); + _referenceFileWatchingTokens.Remove(fullFilePath); - _previousDisposalLocations.Remove(reference); - _previousDisposalLocations.Add(reference, disposalLocation); + if (referenceToTrack != null) + { + _previousDisposalLocations.Remove(referenceToTrack); + _previousDisposalLocations.Add(referenceToTrack, disposalLocation); + } } else { - _metadataReferenceFileWatchingTokens[reference] = (watchedFileReference.Token, newRefCount); + _referenceFileWatchingTokens[fullFilePath] = (watchedFileReference.Token, newRefCount); } - // Note we still potentially have an outstanding change that we haven't raised a notification - // for due to the delay we use. We could cancel the notification for that file path, - // but we may still have another outstanding PortableExecutableReference that isn't this one - // that does want that notification. We're OK just leaving the delay still running for two - // reasons: + // Note we still potentially have an outstanding change that we haven't raised a notification for due to the + // delay we use. We could cancel the notification for that file path, but we may still have another + // outstanding PortableExecutableReference that isn't this one that does want that notification. We're OK + // just leaving the delay still running for two reasons: // - // 1. Technically, we did see a file change before the call to StopWatchingReference, so - // arguably we should still raise it. - // 2. Since we raise the notification for a file path, it's up to the consumer of this to still - // track down which actual reference needs to be changed. That'll automatically handle any - // race where the event comes late, which is a scenario this must always deal with no matter - // what -- another thread might already be gearing up to notify the caller of this reference - // and we can't stop it. + // 1. Technically, we did see a file change before the call to StopWatchingReference, so arguably we should + // still raise it. + // 2. Since we raise the notification for a file path, it's up to the consumer of this to still track down + // which actual reference needs to be changed. That'll automatically handle any race where the event + // comes late, which is a scenario this must always deal with no matter what -- another thread might + // already be gearing up to notify the caller of this reference and we can't stop it. } } - private void FileReferenceChangeContext_FileChanged(object? sender, string fullFilePath) + private async ValueTask ProcessWorkAsync(ImmutableSegmentedList list, CancellationToken cancellationToken) { - lock (_gate) - { - if (_metadataReferenceRefreshCancellationTokenSources.TryGetValue(fullFilePath, out var cancellationTokenSource)) - { - cancellationTokenSource.Cancel(); - _metadataReferenceRefreshCancellationTokenSources.Remove(fullFilePath); - } - - cancellationTokenSource = new CancellationTokenSource(); - _metadataReferenceRefreshCancellationTokenSources.Add(fullFilePath, cancellationTokenSource); - - Task.Delay(TimeSpan.FromSeconds(5), cancellationTokenSource.Token).ContinueWith(_ => - { - var needsNotification = false; - - lock (_gate) - { - // We need to re-check the cancellation token source under the lock, since it might have been cancelled and restarted - // due to another event - cancellationTokenSource.Token.ThrowIfCancellationRequested(); - needsNotification = true; - - _metadataReferenceRefreshCancellationTokenSources.Remove(fullFilePath); - } - - if (needsNotification) - { - ReferenceChanged?.Invoke(this, fullFilePath); - } - }, cancellationTokenSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default); - } + foreach (var filePath in list) + await _callback(filePath, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IFileChangeWatcher.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IFileChangeWatcher.cs index 9768328a868b0..0e7a9612cef12 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IFileChangeWatcher.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IFileChangeWatcher.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.ProjectSystem; internal interface IFileChangeWatcher { - IFileChangeContext CreateContext(params WatchedDirectory[] watchedDirectories); + IFileChangeContext CreateContext(ImmutableArray watchedDirectories); } /// diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IProjectSystemDiagnosticSource.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IProjectSystemDiagnosticSource.cs deleted file mode 100644 index 272c88bc422f7..0000000000000 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/IProjectSystemDiagnosticSource.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CodeAnalysis.Diagnostics; - -namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem; - -// TODO: see if we can get rid of this interface by appropriately rewriting HostDiagnosticUpdateSource to live at the workspaces layer. -internal interface IProjectSystemDiagnosticSource -{ - DiagnosticData CreateAnalyzerLoadFailureDiagnostic(AnalyzerLoadFailureEventArgs e, string fullPath, ProjectId projectId, string language); -} diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.BatchingDocumentCollection.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.BatchingDocumentCollection.cs index e017706f08eea..d0d9ffcd09ec1 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.BatchingDocumentCollection.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.BatchingDocumentCollection.cs @@ -405,7 +405,7 @@ public async ValueTask ProcessRegularFileChangesAsync(ImmutableSegmentedList d.Id == documentId)) { - documentsToChange.Add((documentId, new WorkspaceFileTextLoader(_project._projectSystemProjectFactory.Workspace.Services.SolutionServices, filePath, defaultEncoding: null))); + documentsToChange.Add((documentId, new WorkspaceFileTextLoader(_project._projectSystemProjectFactory.SolutionServices, filePath, defaultEncoding: null))); } } } @@ -428,6 +428,7 @@ await _project._projectSystemProjectFactory.ApplyBatchChangeToWorkspaceAsync((so [documentId]); } } + return projectUpdateState; }, onAfterUpdateAlways: null).ConfigureAwait(false); diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs index a7e8a7c5b17d5..b963a26744eaa 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs @@ -38,9 +38,10 @@ internal sealed partial class ProjectSystemProject /// /// A semaphore taken for all mutation of any mutable field in this type. /// - /// This is, for now, intentionally pessimistic. There are no doubt ways that we could allow more to run in parallel, - /// but the current tradeoff is for simplicity of code and "obvious correctness" than something that is subtle, fast, and wrong. - private readonly SemaphoreSlim _gate = new SemaphoreSlim(initialCount: 1); + /// This is, for now, intentionally pessimistic. There are no doubt ways that we could allow more to run in + /// parallel, but the current tradeoff is for simplicity of code and "obvious correctness" than something that is + /// subtle, fast, and wrong. + private readonly SemaphoreSlim _gate = new(initialCount: 1); /// /// The number of active batch scopes. If this is zero, we are not batching, non-zero means we are batching. @@ -52,14 +53,20 @@ internal sealed partial class ProjectSystemProject private readonly List _projectReferencesAddedInBatch = []; private readonly List _projectReferencesRemovedInBatch = []; - private readonly Dictionary _analyzerPathsToAnalyzers = []; - private readonly List _analyzersAddedInBatch = []; + /// + /// The set of actual analyzer reference paths that the project knows about. + /// + private readonly HashSet _projectAnalyzerPaths = []; /// - /// The list of that will be removed in this batch. They have not yet - /// been disposed, and will be disposed once the batch is applied. + /// Paths to analyzers we want to add when the current batch completes. /// - private readonly List _analyzersRemovedInBatch = []; + private readonly List _analyzersAddedInBatch = []; + + /// + /// Paths to analzyers we want to remove when the current batch completes. + /// + private readonly List _analyzersRemovedInBatch = []; private readonly List> _projectPropertyModificationsInBatch = []; @@ -150,8 +157,7 @@ internal ProjectSystemProject( string assemblyName, CompilationOptions? compilationOptions, string? filePath, - ParseOptions? parseOptions, - string? compilationOutputAssemblyFilePath) + ParseOptions? parseOptions) { _projectSystemProjectFactory = projectSystemProjectFactory; _hostInfo = hostInfo; @@ -160,11 +166,10 @@ internal ProjectSystemProject( Language = language; _displayName = displayName; - var provider = _projectSystemProjectFactory.Workspace.Services.GetRequiredService(); - // Shadow copy analyzer files coming from packages to avoid locking the files in NuGet cache. - // NOTE: The provider will always return the same singleton analyzer loader instance, which is important to - // ensure that shadow copied analyzer dependencies are correctly loaded. - _analyzerAssemblyLoader = provider.GetLoader(shadowCopy: true); + var provider = _projectSystemProjectFactory.SolutionServices.GetRequiredService(); + // NOTE: The provider will always return the same singleton, shadow copying, analyzer loader instance, which is + // important to ensure that analyzer dependencies are correctly loaded. + _analyzerAssemblyLoader = provider.SharedShadowCopyLoader; _sourceFiles = new BatchingDocumentCollection( this, @@ -199,24 +204,19 @@ internal ProjectSystemProject( _compilationOptions = compilationOptions; _filePath = filePath; _parseOptions = parseOptions; - _compilationOutputAssemblyFilePath = compilationOutputAssemblyFilePath; var watchedDirectories = GetWatchedDirectories(language, filePath); _documentFileChangeContext = _projectSystemProjectFactory.FileChangeWatcher.CreateContext(watchedDirectories); _documentFileChangeContext.FileChanged += DocumentFileChangeContext_FileChanged; - static WatchedDirectory[] GetWatchedDirectories(string? language, string? filePath) + static ImmutableArray GetWatchedDirectories(string? language, string? filePath) { if (filePath is null) - { return []; - } var rootPath = Path.GetDirectoryName(filePath); if (rootPath is null) - { return []; - } return language switch { @@ -246,6 +246,8 @@ private void ChangeProjectProperty( Func updateSolution, bool logThrowAwayTelemetry = false) { + using var _ = CreateBatchScope(); + using (_gate.DisposableWait()) { // If nothing is changing, we can skip entirely @@ -260,11 +262,11 @@ private void ChangeProjectProperty( if (logThrowAwayTelemetry) { - var telemetryService = _projectSystemProjectFactory.Workspace.Services.GetService(); + var telemetryService = _projectSystemProjectFactory.SolutionServices.GetService(); if (telemetryService?.HasActiveSession == true) { - var workspaceStatusService = _projectSystemProjectFactory.Workspace.Services.GetRequiredService(); + var workspaceStatusService = _projectSystemProjectFactory.SolutionServices.GetRequiredService(); // We only log telemetry during solution open @@ -283,17 +285,8 @@ private void ChangeProjectProperty( } } - if (_activeBatchScopes > 0) - { - _projectPropertyModificationsInBatch.Add( - (solutionChanges, projectUpdateState) => updateSolution(solutionChanges, projectUpdateState, oldValue)); - } - else - { - _projectSystemProjectFactory.ApplyBatchChangeToWorkspace( - (solutionChanges, projectUpdateState) => updateSolution(solutionChanges, projectUpdateState, oldValue), - onAfterUpdateAlways: null); - } + _projectPropertyModificationsInBatch.Add( + (solutionChanges, projectUpdateState) => updateSolution(solutionChanges, projectUpdateState, oldValue)); } } @@ -383,9 +376,9 @@ internal string? CompilationOutputAssemblyFilePath { get => _compilationOutputAssemblyFilePath; set => ChangeProjectOutputPath( - ref _compilationOutputAssemblyFilePath, - value, - s => s.WithProjectCompilationOutputInfo(Id, s.GetRequiredProject(Id).CompilationOutputInfo.WithAssemblyPath(value))); + ref _compilationOutputAssemblyFilePath, + value, + s => s.WithProjectCompilationOutputInfo(Id, s.GetRequiredProject(Id).CompilationOutputInfo.WithAssemblyPath(value))); } public string? OutputFilePath @@ -563,7 +556,8 @@ private async Task OnBatchScopeDisposedMaybeAsync(bool useAsync) await _projectSystemProjectFactory.ApplyBatchChangeToWorkspaceMaybeAsync(useAsync, (solutionChanges, projectUpdateState) => { - // Changes made inside this transformation must be idemopotent in case it is attempted multiple times. + // Changes made inside this transformation must be idempotent in case it is attempted multiple times. + var projectBeforeMutations = solutionChanges.Solution.GetRequiredProject(Id); var documentFileNamesAddedBuilder = ImmutableArray.CreateBuilder(); documentsToOpen = _sourceFiles.UpdateSolutionForBatch( @@ -592,91 +586,18 @@ await _projectSystemProjectFactory.ApplyBatchChangeToWorkspaceMaybeAsync(useAsyn documentFileNamesAdded = documentFileNamesAddedBuilder.ToImmutable(); - // Metadata reference removing. Do this before adding in case this removes a project reference that - // we are also going to add in the same batch. This could happen if case is changing, or we're targeting - // a different output path (say bin vs. obj vs. ref). - foreach (var (path, properties) in _metadataReferencesRemovedInBatch) - { - projectUpdateState = TryRemoveConvertedProjectReference_NoLock(Id, path, properties, projectUpdateState, out var projectReference); - - if (projectReference != null) - { - solutionChanges.UpdateSolutionForProjectAction( - Id, - solutionChanges.Solution.RemoveProjectReference(Id, projectReference)); - } - else - { - // TODO: find a cleaner way to fetch this - var metadataReference = _projectSystemProjectFactory.Workspace.CurrentSolution.GetRequiredProject(Id).MetadataReferences.Cast() - .Single(m => m.FilePath == path && m.Properties == properties); - - projectUpdateState = projectUpdateState.WithIncrementalReferenceRemoved(metadataReference); + projectUpdateState = UpdateMetadataReferences( + projectBeforeMutations, solutionChanges, projectUpdateState, _metadataReferencesRemovedInBatch, _metadataReferencesAddedInBatch); - solutionChanges.UpdateSolutionForProjectAction( - Id, - newSolution: solutionChanges.Solution.RemoveMetadataReference(Id, metadataReference)); - } - } + UpdateProjectReferences( + Id, solutionChanges, _projectReferencesRemovedInBatch, _projectReferencesAddedInBatch); - // Metadata reference adding... - if (_metadataReferencesAddedInBatch.Count > 0) - { - var projectReferencesCreated = new List(); - - foreach (var (path, properties) in _metadataReferencesAddedInBatch) - { - projectUpdateState = TryCreateConvertedProjectReference_NoLock( - Id, path, properties, projectUpdateState, solutionChanges.Solution, out var projectReference); - - if (projectReference != null) - { - projectReferencesCreated.Add(projectReference); - } - else - { - var metadataReference = CreateReference_NoLock(path, properties, _projectSystemProjectFactory.SolutionServices); - projectUpdateState = projectUpdateState.WithIncrementalReferenceAdded(metadataReference); - } - } - - solutionChanges.UpdateSolutionForProjectAction( - Id, - solutionChanges.Solution.AddProjectReferences(Id, projectReferencesCreated) - .AddMetadataReferences(Id, projectUpdateState.AddedReferences)); - } - - // Project reference adding... - solutionChanges.UpdateSolutionForProjectAction( - Id, - newSolution: solutionChanges.Solution.AddProjectReferences(Id, _projectReferencesAddedInBatch)); - - // Project reference removing... - foreach (var projectReference in _projectReferencesRemovedInBatch) - { - solutionChanges.UpdateSolutionForProjectAction( - Id, - newSolution: solutionChanges.Solution.RemoveProjectReference(Id, projectReference)); - } - - // Analyzer reference adding... - solutionChanges.UpdateSolutionForProjectAction( - Id, - newSolution: solutionChanges.Solution.AddAnalyzerReferences(Id, _analyzersAddedInBatch.Select(a => a.GetReference()))); - - // Analyzer reference removing... - foreach (var analyzerReference in _analyzersRemovedInBatch) - { - solutionChanges.UpdateSolutionForProjectAction( - Id, - newSolution: solutionChanges.Solution.RemoveAnalyzerReference(Id, analyzerReference.GetReference())); - } + projectUpdateState = UpdateAnalyzerReferences( + projectBeforeMutations, solutionChanges, projectUpdateState, _analyzersRemovedInBatch, _analyzersAddedInBatch); // Other property modifications... foreach (var propertyModification in _projectPropertyModificationsInBatch) - { projectUpdateState = propertyModification(solutionChanges, projectUpdateState); - } return projectUpdateState; }, @@ -695,15 +616,7 @@ await _projectSystemProjectFactory.ApplyBatchChangeToWorkspaceMaybeAsync(useAsyn ClearAndZeroCapacity(_projectReferencesAddedInBatch); ClearAndZeroCapacity(_projectReferencesRemovedInBatch); ClearAndZeroCapacity(_analyzersAddedInBatch); - if (_analyzersRemovedInBatch.Count > 0) - { - // Dispose of any analyzers that were removed now that we've applied the changes. - foreach (var analyzer in _analyzersRemovedInBatch) - { - analyzer.Dispose(); - } - ClearAndZeroCapacity(_analyzersRemovedInBatch); - } + ClearAndZeroCapacity(_analyzersRemovedInBatch); ClearAndZeroCapacity(_projectPropertyModificationsInBatch); @@ -726,6 +639,129 @@ await _projectSystemProjectFactory.ApplyBatchChangeToWorkspaceMaybeAsync(useAsyn if (hasAnalyzerChanges) _projectSystemProjectFactory.Workspace.EnqueueUpdateSourceGeneratorVersion(projectId: null, forceRegeneration: true); } + + static ProjectUpdateState UpdateMetadataReferences( + Project projectBeforeMutation, + SolutionChangeAccumulator solutionChanges, + ProjectUpdateState projectUpdateState, + List<(string path, MetadataReferenceProperties properties)> metadataReferencesRemovedInBatch, + List<(string path, MetadataReferenceProperties properties)> metadataReferencesAddedInBatch) + { + var projectId = projectBeforeMutation.Id; + + // Metadata reference removing. Do this before adding in case this removes a project reference that we are also + // going to add in the same batch. This could happen if case is changing, or we're targeting a different output + // path (say bin vs. obj vs. ref). + foreach (var (path, properties) in metadataReferencesRemovedInBatch) + { + projectUpdateState = TryRemoveConvertedProjectReference_NoLock(projectId, path, properties, projectUpdateState, out var projectReference); + + if (projectReference != null) + { + solutionChanges.UpdateSolutionForProjectAction( + projectId, solutionChanges.Solution.RemoveProjectReference(projectId, projectReference)); + } + else + { + var metadataReference = projectBeforeMutation.MetadataReferences + .OfType() + .Single(m => m.FilePath == path && m.Properties == properties); + + projectUpdateState = projectUpdateState.WithIncrementalMetadataReferenceRemoved(metadataReference); + + solutionChanges.UpdateSolutionForProjectAction( + projectId, solutionChanges.Solution.RemoveMetadataReference(projectId, metadataReference)); + } + } + + // Metadata reference adding... + if (metadataReferencesAddedInBatch.Count > 0) + { + var projectReferencesCreated = new List(); + + foreach (var (path, properties) in metadataReferencesAddedInBatch) + { + projectUpdateState = TryCreateConvertedProjectReference_NoLock( + projectId, path, properties, projectUpdateState, solutionChanges.Solution, out var projectReference); + + if (projectReference != null) + { + projectReferencesCreated.Add(projectReference); + } + else + { + var metadataReference = CreateMetadataReference_NoLock(path, properties, solutionChanges.Solution.Services); + projectUpdateState = projectUpdateState.WithIncrementalMetadataReferenceAdded(metadataReference); + } + } + + solutionChanges.UpdateSolutionForProjectAction( + projectId, + solutionChanges.Solution + .AddProjectReferences(projectId, projectReferencesCreated) + .AddMetadataReferences(projectId, projectUpdateState.AddedMetadataReferences)); + } + + return projectUpdateState; + } + + static void UpdateProjectReferences( + ProjectId projectId, + SolutionChangeAccumulator solutionChanges, + List projectReferencesRemovedInBatch, + List projectReferencesAddedInBatch) + { + // Project reference adding... + solutionChanges.UpdateSolutionForProjectAction( + projectId, solutionChanges.Solution.AddProjectReferences(projectId, projectReferencesAddedInBatch)); + + // Project reference removing... + foreach (var projectReference in projectReferencesRemovedInBatch) + { + solutionChanges.UpdateSolutionForProjectAction( + projectId, solutionChanges.Solution.RemoveProjectReference(projectId, projectReference)); + } + } + + static ProjectUpdateState UpdateAnalyzerReferences( + Project projectBeforeMutation, + SolutionChangeAccumulator solutionChanges, + ProjectUpdateState projectUpdateState, + List analyzersRemovedInBatch, + List analyzersAddedInBatch) + { + var projectId = projectBeforeMutation.Id; + + // Analyzer reference removing... + if (analyzersRemovedInBatch.Count > 0) + { + projectUpdateState = projectUpdateState.WithIncrementalAnalyzerReferencesRemoved(analyzersRemovedInBatch); + + foreach (var analyzerReferenceFullPath in analyzersRemovedInBatch) + { + solutionChanges.UpdateSolutionForProjectAction( + projectId, + solutionChanges.Solution.RemoveAnalyzerReference( + projectId, projectBeforeMutation.AnalyzerReferences.First(a => a.FullPath == analyzerReferenceFullPath))); + } + } + + // Analyzer reference adding... + if (analyzersAddedInBatch.Count > 0) + { + projectUpdateState = projectUpdateState.WithIncrementalAnalyzerReferencesAdded(analyzersAddedInBatch); + + var loaderProvider = solutionChanges.Solution.Services.GetRequiredService(); + var shadowCopyLoader = loaderProvider.SharedShadowCopyLoader; + + solutionChanges.UpdateSolutionForProjectAction( + projectId, + solutionChanges.Solution.AddAnalyzerReferences(projectId, + analyzersAddedInBatch.Select(fullPath => new AnalyzerFileReference(fullPath, shadowCopyLoader)))); + } + + return projectUpdateState; + } } #endregion @@ -934,47 +970,31 @@ public void AddAnalyzerReference(string fullPath) var mappedPaths = GetMappedAnalyzerPaths(fullPath); + using var _ = CreateBatchScope(); + using (_gate.DisposableWait()) { // check all mapped paths first, so that all analyzers are either added or not foreach (var mappedFullPath in mappedPaths) { - if (_analyzerPathsToAnalyzers.ContainsKey(mappedFullPath)) - { + if (_projectAnalyzerPaths.Contains(mappedFullPath)) throw new ArgumentException($"'{fullPath}' has already been added to this project.", nameof(fullPath)); - } } foreach (var mappedFullPath in mappedPaths) { - // Are we adding one we just recently removed? If so, we can just keep using that one, and avoid removing - // it once we apply the batch - var analyzerPendingRemoval = _analyzersRemovedInBatch.FirstOrDefault(a => a.FullPath == mappedFullPath); + // Are we adding one we just recently removed? If so, we can just keep using that one, and avoid + // removing it once we apply the batch + var analyzerPendingRemoval = _analyzersRemovedInBatch.FirstOrDefault(fullPath => fullPath == mappedFullPath); + _projectAnalyzerPaths.Add(mappedFullPath); + if (analyzerPendingRemoval != null) { _analyzersRemovedInBatch.Remove(analyzerPendingRemoval); - _analyzerPathsToAnalyzers.Add(mappedFullPath, analyzerPendingRemoval); } else { - // Nope, we actually need to make a new one. - var visualStudioAnalyzer = new ProjectAnalyzerReference( - mappedFullPath, - _analyzerAssemblyLoader, - _hostInfo.DiagnosticSource, - Id, - Language); - - _analyzerPathsToAnalyzers.Add(mappedFullPath, visualStudioAnalyzer); - - if (_activeBatchScopes > 0) - { - _analyzersAddedInBatch.Add(visualStudioAnalyzer); - } - else - { - _projectSystemProjectFactory.ApplyChangeToWorkspace(w => w.OnAnalyzerReferenceAdded(Id, visualStudioAnalyzer.GetReference())); - } + _analyzersAddedInBatch.Add(mappedFullPath); } } } @@ -983,49 +1003,29 @@ public void AddAnalyzerReference(string fullPath) public void RemoveAnalyzerReference(string fullPath) { if (string.IsNullOrEmpty(fullPath)) - { throw new ArgumentException("message", nameof(fullPath)); - } var mappedPaths = GetMappedAnalyzerPaths(fullPath); + using var _ = CreateBatchScope(); + using (_gate.DisposableWait()) { // check all mapped paths first, so that all analyzers are either removed or not foreach (var mappedFullPath in mappedPaths) { - if (!_analyzerPathsToAnalyzers.ContainsKey(mappedFullPath)) - { + if (!_projectAnalyzerPaths.Contains(mappedFullPath)) throw new ArgumentException($"'{fullPath}' is not an analyzer of this project.", nameof(fullPath)); - } } foreach (var mappedFullPath in mappedPaths) { - var visualStudioAnalyzer = _analyzerPathsToAnalyzers[mappedFullPath]; - - _analyzerPathsToAnalyzers.Remove(mappedFullPath); - - if (_activeBatchScopes > 0) - { - // This analyzer may be one we've just added in the same batch; in that case, just don't add - // it in the first place. - if (_analyzersAddedInBatch.Remove(visualStudioAnalyzer)) - { - // Nothing is holding onto this analyzer now, so get rid of it - visualStudioAnalyzer.Dispose(); - } - else - { - _analyzersRemovedInBatch.Add(visualStudioAnalyzer); - } - } - else - { - _projectSystemProjectFactory.ApplyChangeToWorkspace(w => w.OnAnalyzerReferenceRemoved(Id, visualStudioAnalyzer.GetReference())); + _projectAnalyzerPaths.Remove(mappedFullPath); - visualStudioAnalyzer.Dispose(); - } + // This analyzer may be one we've just added in the same batch; in that case, just don't add it in + // the first place. + if (!_analyzersAddedInBatch.Remove(mappedFullPath)) + _analyzersRemovedInBatch.Add(mappedFullPath); } } } @@ -1087,46 +1087,19 @@ private async ValueTask ProcessFileChangesAsync(ImmutableSegmentedList f public void AddMetadataReference(string fullPath, MetadataReferenceProperties properties) { if (string.IsNullOrEmpty(fullPath)) - { throw new ArgumentException($"{nameof(fullPath)} isn't a valid path.", nameof(fullPath)); - } + + using var _ = CreateBatchScope(); using (_gate.DisposableWait()) { if (ContainsMetadataReference_NoLock(fullPath, properties)) - { throw new InvalidOperationException("The metadata reference has already been added to the project."); - } _allMetadataReferences.MultiAdd(fullPath, properties, s_defaultMetadataReferenceProperties); - if (_activeBatchScopes > 0) - { - if (!_metadataReferencesRemovedInBatch.Remove((fullPath, properties))) - { - _metadataReferencesAddedInBatch.Add((fullPath, properties)); - } - } - else - { - _projectSystemProjectFactory.ApplyChangeToWorkspaceWithProjectUpdateState((w, projectUpdateState) => - { - projectUpdateState = ProjectSystemProjectFactory.TryCreateConvertedProjectReference_NoLock(Id, fullPath, properties, projectUpdateState, w.CurrentSolution, out var projectReference); - - if (projectReference != null) - { - w.OnProjectReferenceAdded(Id, projectReference); - } - else - { - var metadataReference = CreateReference_NoLock(fullPath, properties, _projectSystemProjectFactory.SolutionServices); - projectUpdateState = projectUpdateState.WithIncrementalReferenceAdded(metadataReference); - w.OnMetadataReferenceAdded(Id, metadataReference); - } - - return projectUpdateState; - }); - } + if (!_metadataReferencesRemovedInBatch.Remove((fullPath, properties))) + _metadataReferencesAddedInBatch.Add((fullPath, properties)); } } @@ -1160,49 +1133,19 @@ public ImmutableArray GetPropertiesForMetadataRefer public void RemoveMetadataReference(string fullPath, MetadataReferenceProperties properties) { if (string.IsNullOrEmpty(fullPath)) - { throw new ArgumentException($"{nameof(fullPath)} isn't a valid path.", nameof(fullPath)); - } + + using var _ = CreateBatchScope(); using (_gate.DisposableWait()) { if (!ContainsMetadataReference_NoLock(fullPath, properties)) - { throw new InvalidOperationException("The metadata reference does not exist in this project."); - } _allMetadataReferences.MultiRemove(fullPath, properties); - if (_activeBatchScopes > 0) - { - if (!_metadataReferencesAddedInBatch.Remove((fullPath, properties))) - { - _metadataReferencesRemovedInBatch.Add((fullPath, properties)); - } - } - else - { - _projectSystemProjectFactory.ApplyChangeToWorkspaceWithProjectUpdateState((w, projectUpdateState) => - { - projectUpdateState = TryRemoveConvertedProjectReference_NoLock(Id, fullPath, properties, projectUpdateState, out var projectReference); - - // If this was converted to a project reference, we have now recorded the removal -- let's remove it here too - if (projectReference != null) - { - w.OnProjectReferenceRemoved(Id, projectReference); - } - else - { - // TODO: find a cleaner way to fetch this - var metadataReference = w.CurrentSolution.GetRequiredProject(Id).MetadataReferences.Cast() - .Single(m => m.FilePath == fullPath && m.Properties == properties); - projectUpdateState = projectUpdateState.WithIncrementalReferenceRemoved(metadataReference); - w.OnMetadataReferenceRemoved(Id, metadataReference); - } - - return projectUpdateState; - }); - } + if (!_metadataReferencesAddedInBatch.Remove((fullPath, properties))) + _metadataReferencesRemovedInBatch.Add((fullPath, properties)); } } @@ -1213,37 +1156,24 @@ public void RemoveMetadataReference(string fullPath, MetadataReferenceProperties public void AddProjectReference(ProjectReference projectReference) { if (projectReference == null) - { throw new ArgumentNullException(nameof(projectReference)); - } + + using var _ = CreateBatchScope(); using (_gate.DisposableWait()) { if (ContainsProjectReference_NoLock(projectReference)) - { throw new ArgumentException("The project reference has already been added to the project."); - } - if (_activeBatchScopes > 0) - { - if (!_projectReferencesRemovedInBatch.Remove(projectReference)) - { - _projectReferencesAddedInBatch.Add(projectReference); - } - } - else - { - _projectSystemProjectFactory.ApplyChangeToWorkspace(w => w.OnProjectReferenceAdded(Id, projectReference)); - } + if (!_projectReferencesRemovedInBatch.Remove(projectReference)) + _projectReferencesAddedInBatch.Add(projectReference); } } public bool ContainsProjectReference(ProjectReference projectReference) { if (projectReference == null) - { throw new ArgumentNullException(nameof(projectReference)); - } using (_gate.DisposableWait()) { @@ -1256,14 +1186,10 @@ private bool ContainsProjectReference_NoLock(ProjectReference projectReference) Debug.Assert(_gate.CurrentCount == 0); if (_projectReferencesRemovedInBatch.Contains(projectReference)) - { return false; - } if (_projectReferencesAddedInBatch.Contains(projectReference)) - { return true; - } return _projectSystemProjectFactory.Workspace.CurrentSolution.GetRequiredProject(Id).AllProjectReferences.Contains(projectReference); } @@ -1292,28 +1218,17 @@ public IReadOnlyList GetProjectReferences() public void RemoveProjectReference(ProjectReference projectReference) { if (projectReference == null) - { throw new ArgumentNullException(nameof(projectReference)); - } + + using var _ = CreateBatchScope(); using (_gate.DisposableWait()) { if (!ContainsProjectReference_NoLock(projectReference)) - { throw new ArgumentException("The project does not contain that project reference."); - } - if (_activeBatchScopes > 0) - { - if (!_projectReferencesAddedInBatch.Remove(projectReference)) - { - _projectReferencesRemovedInBatch.Add(projectReference); - } - } - else - { - _projectSystemProjectFactory.ApplyChangeToWorkspace(w => w.OnProjectReferenceRemoved(Id, projectReference)); - } + if (!_projectReferencesAddedInBatch.Remove(projectReference)) + _projectReferencesRemovedInBatch.Add(projectReference); } } @@ -1365,16 +1280,8 @@ public void RemoveFromWorkspace() Contract.ThrowIfNull(remainingMetadataReferences); - foreach (PortableExecutableReference reference in remainingMetadataReferences) - { - _projectSystemProjectFactory.FileWatchedReferenceFactory.StopWatchingReference(reference); - } - - // Dispose of any analyzers that might still be around to remove their load diagnostics - foreach (var visualStudioAnalyzer in _analyzerPathsToAnalyzers.Values.Concat(_analyzersRemovedInBatch)) - { - visualStudioAnalyzer.Dispose(); - } + foreach (var reference in remainingMetadataReferences.OfType()) + _projectSystemProjectFactory.FileWatchedPortableExecutableReferenceFactory.StopWatchingReference(reference.FilePath!, referenceToTrack: reference); } public void ReorderSourceFiles(ImmutableArray filePaths) diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.ProjectUpdateState.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.ProjectUpdateState.cs index f376d94df707c..93962e6fa2e0f 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.ProjectUpdateState.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.ProjectUpdateState.cs @@ -3,52 +3,63 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Diagnostics; namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem; internal sealed partial class ProjectSystemProjectFactory { /// - /// Immutable data type that holds the current state of the project system factory as well as - /// storing any incremental state changes in the current workspace update. + /// Immutable data type that holds the current state of the project system factory as well as storing any + /// incremental state changes in the current workspace update. /// - /// This state is updated by various project system update operations under the . - /// Importantly, this immutable type allows us to discard updates to the state that fail to apply - /// due to interceding workspace operations. + /// This state is updated by various project system update operations under the . Importantly, + /// this immutable type allows us to discard updates to the state that fail to apply due to interceding workspace + /// operations. /// /// There are two kinds of state that this type holds that need to support discarding: - /// 1. Global state for the (various maps of project information). - /// This state must be saved between different changes. - /// 2. Incremental state for the current change being processed. This state has information that is - /// cannot be resilient to being applied multiple times during the workspace update, so is saved - /// to be applied only once the workspace update is successful. - /// + /// + /// Global state for the (various maps of project information). This + /// state must be saved between different changes. + /// Incremental state for the current change being processed. This state has information that is cannot be + /// resilient to being applied multiple times during the workspace update, so is saved to be applied only once the + /// workspace update is successful. + /// /// /// - /// Global state representing a multimap from an output path to the project outputting to it. Ideally, this shouldn't ever - /// actually be a true multimap, since we shouldn't have two projects outputting to the same path, but - /// any bug by a project adding the wrong output path means we could end up with some duplication. - /// In that case, we'll temporarily have two until (hopefully) somebody removes it. + /// Global state representing a multimap from an output path to the project outputting to it. Ideally, this + /// shouldn't ever actually be a true multimap, since we shouldn't have two projects outputting to the same path, + /// but any bug by a project adding the wrong output path means we could end up with some duplication. In that case, + /// we'll temporarily have two until (hopefully) somebody removes it. /// /// /// Global state containing output paths and converted project reference information for each project. /// - /// - /// Incremental state containing references removed in the current update. + /// + /// Incremental state containing metadata references removed in the current update. /// - /// - /// Incremental state containing references added in the current update. + /// + /// Incremental state containing metadata references added in the current update. + /// + /// + /// Incremental state containing analyzer references removed in the current update. + /// + /// + /// Incremental state containing analyzer references added in the current update. /// public sealed record class ProjectUpdateState( ImmutableDictionary> ProjectsByOutputPath, ImmutableDictionary ProjectReferenceInfos, - ImmutableArray RemovedReferences, - ImmutableArray AddedReferences) + ImmutableArray RemovedMetadataReferences, + ImmutableArray AddedMetadataReferences, + ImmutableArray RemovedAnalyzerReferences, + ImmutableArray AddedAnalyzerReferences) { public static ProjectUpdateState Empty = new( ImmutableDictionary>.Empty.WithComparers(StringComparer.OrdinalIgnoreCase), - ImmutableDictionary.Empty, [], []); + ImmutableDictionary.Empty, [], [], [], []); public ProjectUpdateState WithProjectReferenceInfo(ProjectId projectId, ProjectReferenceInformation projectReferenceInformation) { @@ -104,33 +115,35 @@ static ImmutableDictionary> RemoveProject(stri } } - public ProjectUpdateState WithIncrementalReferenceRemoved(PortableExecutableReference reference) - { - return this with - { - RemovedReferences = RemovedReferences.Add(reference) - }; - } + public ProjectUpdateState WithIncrementalMetadataReferenceRemoved(PortableExecutableReference reference) + => this with { RemovedMetadataReferences = RemovedMetadataReferences.Add(reference) }; - public ProjectUpdateState WithIncrementalReferenceAdded(PortableExecutableReference reference) - { - return this with - { - AddedReferences = AddedReferences.Add(reference) - }; - } + public ProjectUpdateState WithIncrementalMetadataReferenceAdded(PortableExecutableReference reference) + => this with { AddedMetadataReferences = AddedMetadataReferences.Add(reference) }; + + public ProjectUpdateState WithIncrementalAnalyzerReferenceRemoved(string reference) + => this with { RemovedAnalyzerReferences = RemovedAnalyzerReferences.Add(reference) }; + + public ProjectUpdateState WithIncrementalAnalyzerReferencesRemoved(List references) + => this with { RemovedAnalyzerReferences = RemovedAnalyzerReferences.AddRange(references) }; + + public ProjectUpdateState WithIncrementalAnalyzerReferenceAdded(string reference) + => this with { AddedAnalyzerReferences = AddedAnalyzerReferences.Add(reference) }; + + public ProjectUpdateState WithIncrementalAnalyzerReferencesAdded(List references) + => this with { AddedAnalyzerReferences = AddedAnalyzerReferences.AddRange(references) }; /// /// Returns a new instance with any incremental state that should not be saved between updates cleared. /// public ProjectUpdateState ClearIncrementalState() - { - return this with + => this with { - RemovedReferences = [], - AddedReferences = [] + RemovedMetadataReferences = [], + AddedMetadataReferences = [], + RemovedAnalyzerReferences = [], + AddedAnalyzerReferences = [], }; - } } public record struct ProjectReferenceInformation(ImmutableArray OutputPaths, ImmutableArray<(string path, ProjectReference ProjectReference)> ConvertedProjectReferences) diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs index cf8c3a1fbe1c3..0981fffb29976 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs @@ -3,11 +3,14 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections; +using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.ProjectSystem; @@ -28,7 +31,7 @@ internal sealed partial class ProjectSystemProjectFactory /// // TODO: we should be able to get rid of this gate in favor of just calling the various workspace methods that acquire the Workspace's // serialization lock and then allow us to update our own state under that lock. - private readonly SemaphoreSlim _gate = new SemaphoreSlim(initialCount: 1); + private readonly SemaphoreSlim _gate = new(initialCount: 1); /// /// Stores the latest state of the project system factory. @@ -39,8 +42,11 @@ internal sealed partial class ProjectSystemProjectFactory public Workspace Workspace { get; } public IAsynchronousOperationListener WorkspaceListener { get; } public IFileChangeWatcher FileChangeWatcher { get; } - public FileWatchedPortableExecutableReferenceFactory FileWatchedReferenceFactory { get; } - public SolutionServices SolutionServices { get; } + + public FileWatchedReferenceFactory FileWatchedPortableExecutableReferenceFactory { get; } + public FileWatchedReferenceFactory FileWatchedAnalyzerReferenceFactory { get; } + + public SolutionServices SolutionServices => this.Workspace.Services.SolutionServices; private readonly Func, Task> _onDocumentsAddedMaybeAsync; private readonly Action _onProjectRemoved; @@ -69,23 +75,27 @@ internal sealed partial class ProjectSystemProjectFactory public string? SolutionPath { get; set; } public Guid SolutionTelemetryId { get; set; } - public ProjectSystemProjectFactory(Workspace workspace, IFileChangeWatcher fileChangeWatcher, Func, Task> onDocumentsAddedMaybeAsync, Action onProjectRemoved) + public ProjectSystemProjectFactory( + Workspace workspace, + IFileChangeWatcher fileChangeWatcher, + Func, Task> onDocumentsAddedMaybeAsync, + Action onProjectRemoved, + CancellationToken cancellationToken) { Workspace = workspace; - WorkspaceListener = workspace.Services.GetRequiredService().GetListener(); - - SolutionServices = workspace.Services.SolutionServices; - FileChangeWatcher = fileChangeWatcher; - FileWatchedReferenceFactory = new FileWatchedPortableExecutableReferenceFactory(fileChangeWatcher); - FileWatchedReferenceFactory.ReferenceChanged += this.StartRefreshingMetadataReferencesForFile; _onDocumentsAddedMaybeAsync = onDocumentsAddedMaybeAsync; _onProjectRemoved = onProjectRemoved; + + WorkspaceListener = this.SolutionServices.GetRequiredService().GetListener(); + + FileWatchedPortableExecutableReferenceFactory = new(fileChangeWatcher, WorkspaceListener, this.StartRefreshingMetadataReferencesForFileAsync, cancellationToken); + FileWatchedAnalyzerReferenceFactory = new(fileChangeWatcher, WorkspaceListener, this.StartRefreshingAnalyzerReferenceForFileAsync, cancellationToken); } public FileTextLoader CreateFileTextLoader(string fullPath) - => new WorkspaceFileTextLoader(this.Workspace.Services.SolutionServices, fullPath, defaultEncoding: null); + => new WorkspaceFileTextLoader(this.SolutionServices, fullPath, defaultEncoding: null); public async Task CreateAndAddToWorkspaceAsync(string projectSystemName, string language, ProjectSystemProjectCreationInfo creationInfo, ProjectSystemHostInfo hostInfo) { @@ -102,8 +112,7 @@ public async Task CreateAndAddToWorkspaceAsync(string proj assemblyName, creationInfo.CompilationOptions, creationInfo.FilePath, - creationInfo.ParseOptions, - creationInfo.CompilationOutputAssemblyFilePath); + creationInfo.ParseOptions); var versionStamp = creationInfo.FilePath != null ? VersionStamp.Create(File.GetLastWriteTimeUtc(creationInfo.FilePath)) @@ -164,6 +173,15 @@ await ApplyChangeToWorkspaceAsync(w => onAfterUpdate: null); }).ConfigureAwait(false); + // Set this value early after solution is created so it is available to Razor. This will get updated + // when the command line is set, but we want a non-null value to be available as soon as possible. + // + // Set the property in a batch; if we set the property directly we'll be taking a synchronous lock here and + // potentially block up thread pool threads. Doing this in a batch means the global lock will be acquired asynchronously. + var disposableBatchScope = await project.CreateBatchScopeAsync(CancellationToken.None).ConfigureAwait(false); + await using var _ = disposableBatchScope.ConfigureAwait(false); + project.CompilationOutputAssemblyFilePath = creationInfo.CompilationOutputAssemblyFilePath; + return project; } @@ -400,37 +418,25 @@ internal void ApplyProjectUpdateState(ProjectUpdateState projectUpdateState) { Contract.ThrowIfFalse(_gate.CurrentCount == 0); - UpdateReferenceFileWatchers(projectUpdateState.RemovedReferences, projectUpdateState.AddedReferences); + // Remove file watchers for any references we're no longer watching. + foreach (var reference in projectUpdateState.RemovedMetadataReferences) + FileWatchedPortableExecutableReferenceFactory.StopWatchingReference(reference.FilePath!, referenceToTrack: reference); + + // Add file watchers for any references we are now watching. + foreach (var reference in projectUpdateState.AddedMetadataReferences) + FileWatchedPortableExecutableReferenceFactory.StartWatchingReference(reference.FilePath!); + + // Remove file watchers for any references we're no longer watching. + foreach (var referenceFullPath in projectUpdateState.RemovedAnalyzerReferences) + FileWatchedAnalyzerReferenceFactory.StopWatchingReference(referenceFullPath, referenceToTrack: null); + + // Add file watchers for any references we are now watching. + foreach (var referenceFullPath in projectUpdateState.AddedAnalyzerReferences) + FileWatchedAnalyzerReferenceFactory.StartWatchingReference(referenceFullPath); // Clear the state from the this update in preparation for the next. projectUpdateState = projectUpdateState.ClearIncrementalState(); _projectUpdateState = projectUpdateState; - return; - - void UpdateReferenceFileWatchers( - ImmutableArray removedReferences, - ImmutableArray addedReferences) - { - // Remove file watchers for any references we're no longer watching. - if (removedReferences.Count() > 0) - { - // Now that we've removed the references from the sln, we can stop watching them. - foreach (var reference in removedReferences) - { - FileWatchedReferenceFactory.StopWatchingReference(reference); - } - } - - // Add file watchers for any references we are now watching. - if (addedReferences.Count() > 0) - { - // Now that we've added the references to the sln, we can start watching them. - foreach (var reference in addedReferences) - { - FileWatchedReferenceFactory.StartWatchingReference(reference, reference.FilePath!); - } - } - } } internal void RemoveSolution_NoLock() @@ -526,9 +532,11 @@ public static ProjectUpdateState AddProjectOutputPath_NoLock( } /// - /// Attempts to convert all metadata references to to a project reference to . + /// Attempts to convert all metadata references to to a project reference to . /// - /// The of the project that could be referenced in place of the output path. + /// The of the project that could be referenced in place + /// of the output path. /// The output path to replace. [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/31306", Constraint = "Avoid calling " + nameof(CodeAnalysis.Solution.GetProject) + " to avoid realizing all projects.")] @@ -542,17 +550,19 @@ private static ProjectUpdateState ConvertMetadataReferencesToProjectReferences_N { if (CanConvertMetadataReferenceToProjectReference(solutionChanges.Solution, projectIdToRetarget, referencedProjectId: projectIdToReference)) { - // PERF: call GetProjectState instead of GetProject, otherwise creating a new project might force all - // Project instances to get created. - foreach (PortableExecutableReference reference in solutionChanges.Solution.GetProjectState(projectIdToRetarget)!.MetadataReferences) + // PERF: call GetRequiredProjectState instead of GetRequiredProject, otherwise creating a new project + // might force all Project instances to get created. + var projectState = solutionChanges.Solution.GetRequiredProjectState(projectIdToRetarget); + foreach (var reference in projectState.MetadataReferences.OfType()) { if (string.Equals(reference.FilePath, outputPath, StringComparison.OrdinalIgnoreCase)) { - projectUpdateState = projectUpdateState.WithIncrementalReferenceRemoved(reference); + projectUpdateState = projectUpdateState.WithIncrementalMetadataReferenceRemoved(reference); var projectReference = new ProjectReference(projectIdToReference, reference.Properties.Aliases, reference.Properties.EmbedInteropTypes); - var newSolution = solutionChanges.Solution.RemoveMetadataReference(projectIdToRetarget, reference) - .AddProjectReference(projectIdToRetarget, projectReference); + var newSolution = solutionChanges.Solution + .RemoveMetadataReference(projectIdToRetarget, reference) + .AddProjectReference(projectIdToRetarget, projectReference); solutionChanges.UpdateSolutionForProjectAction(projectIdToRetarget, newSolution); @@ -560,8 +570,8 @@ private static ProjectUpdateState ConvertMetadataReferencesToProjectReferences_N projectUpdateState = projectUpdateState.WithProjectReferenceInfo(projectIdToRetarget, projectInfo.WithConvertedProjectReference(reference.FilePath!, projectReference)); - // We have converted one, but you could have more than one reference with different aliases - // that we need to convert, so we'll keep going + // We have converted one, but you could have more than one reference with different aliases that + // we need to convert, so we'll keep going } } } @@ -640,14 +650,13 @@ private static ProjectUpdateState ConvertProjectReferencesToMetadataReferences_N if (string.Equals(convertedReference.path, outputPath, StringComparison.OrdinalIgnoreCase) && convertedReference.ProjectReference.ProjectId == projectId) { - var metadataReference = - CreateReference_NoLock( - convertedReference.path, - new MetadataReferenceProperties( - aliases: convertedReference.ProjectReference.Aliases, - embedInteropTypes: convertedReference.ProjectReference.EmbedInteropTypes), - solutionServices); - projectUpdateState = projectUpdateState.WithIncrementalReferenceAdded(metadataReference); + var metadataReference = CreateMetadataReference_NoLock( + convertedReference.path, + new MetadataReferenceProperties( + aliases: convertedReference.ProjectReference.Aliases, + embedInteropTypes: convertedReference.ProjectReference.EmbedInteropTypes), + solutionServices); + projectUpdateState = projectUpdateState.WithIncrementalMetadataReferenceAdded(metadataReference); var newSolution = solutionChanges.Solution.RemoveProjectReference(projectIdToRetarget, convertedReference.ProjectReference) .AddMetadataReference(projectIdToRetarget, metadataReference); @@ -776,7 +785,7 @@ public static ProjectUpdateState RemoveProjectOutputPath_NoLock( if (projectUpdateState.ProjectsByOutputPath.TryGetValue(outputPath, out var remainingProjectsForOutputPath)) { var distinctRemainingProjects = remainingProjectsForOutputPath.Distinct(); - if (distinctRemainingProjects.Count() == 1) + if (distinctRemainingProjects.Length == 1) { // We had more than one project outputting to the same path. Now we're back down to one // so we can reference that one again @@ -797,48 +806,100 @@ public static ProjectUpdateState RemoveProjectOutputPath_NoLock( /// Gets or creates a PortableExecutableReference instance for the given file path and properties. /// Calls to this are expected to be serialized by the caller. /// - public static PortableExecutableReference CreateReference_NoLock(string fullFilePath, MetadataReferenceProperties properties, SolutionServices solutionServices) + public static PortableExecutableReference CreateMetadataReference_NoLock( + string fullFilePath, MetadataReferenceProperties properties, SolutionServices solutionServices) { - var reference = solutionServices.GetRequiredService().GetReference(fullFilePath, properties); - return reference; + return solutionServices.GetRequiredService().GetReference(fullFilePath, properties); } -#pragma warning disable VSTHRD100 // Avoid async void methods - private async void StartRefreshingMetadataReferencesForFile(object? sender, string fullFilePath) -#pragma warning restore VSTHRD100 // Avoid async void methods - { - using var asyncToken = WorkspaceListener.BeginAsyncOperation(nameof(StartRefreshingMetadataReferencesForFile)); + private Task StartRefreshingMetadataReferencesForFileAsync(string fullFilePath, CancellationToken cancellationToken) + => StartRefreshingReferencesForFileAsync( + fullFilePath, + getReferences: static project => project.MetadataReferences.OfType(), + getFilePath: static reference => reference.FilePath!, + createNewReference: static (solutionServices, reference) => CreateMetadataReference_NoLock(reference.FilePath!, reference.Properties, solutionServices), + update: static (solution, projectId, projectUpdateState, oldReference, newReference) => + { + var newSolution = solution + .RemoveMetadataReference(projectId, oldReference) + .AddMetadataReference(projectId, newReference); + var newProjectUpdateState = projectUpdateState + .WithIncrementalMetadataReferenceRemoved(oldReference) + .WithIncrementalMetadataReferenceAdded(newReference); + + return (newSolution, newProjectUpdateState); + }, + cancellationToken); + + private Task StartRefreshingAnalyzerReferenceForFileAsync(string fullFilePath, CancellationToken cancellationToken) + => StartRefreshingReferencesForFileAsync( + fullFilePath, + getReferences: static project => project.AnalyzerReferences.Select(r => r.FullPath!), + getFilePath: static fullPath => fullPath, + createNewReference: static (_, fullPath) => fullPath, + update: static (solution, projectId, projectUpdateState, oldReferenceFullPath, newReferenceFullPath) => + { + // it's expected that the old and new paths are the same here. The idea is that we changed a file on + // disk, so of course the path will be the same. + Contract.ThrowIfTrue(oldReferenceFullPath != newReferenceFullPath); + + var assemblyLoaderProvider = solution.Services.GetRequiredService(); + + var project = solution.GetRequiredProject(projectId); + var oldAnalyzerReference = project.AnalyzerReferences.First(r => r.FullPath == oldReferenceFullPath); + var newAnalyzerReference = new AnalyzerFileReference(oldReferenceFullPath, assemblyLoaderProvider.SharedShadowCopyLoader); + + var newSolution = solution + .RemoveAnalyzerReference(projectId, oldAnalyzerReference) + .AddAnalyzerReference(projectId, newAnalyzerReference); + var newProjectUpdateState = projectUpdateState + .WithIncrementalAnalyzerReferenceRemoved(oldReferenceFullPath) + .WithIncrementalAnalyzerReferenceAdded(newReferenceFullPath); + return (newSolution, newProjectUpdateState); + }, + cancellationToken); + + /// + /// Core helper that handles refreshing the references we have for a particular or . + /// + private async Task StartRefreshingReferencesForFileAsync( + string fullFilePath, + Func> getReferences, + Func getFilePath, + Func createNewReference, + Func update, + CancellationToken cancellationToken) + where TReference : class + { await ApplyBatchChangeToWorkspaceAsync((solutionChanges, projectUpdateState) => { - // Access the current update state under the workspace sync. - foreach (var project in Workspace.CurrentSolution.Projects) + var initialSolution = solutionChanges.Solution; + var solutionServices = initialSolution.Services; + foreach (var project in initialSolution.Projects) { - // Loop to find each reference with the given path. It's possible that there might be multiple references of the same path; - // the project system could concievably add the same reference multiple times but with different aliases. It's also possible - // we might not find the path at all: when we receive the file changed event, we aren't checking if the file is still - // in the workspace at that time; it's possible it might have already been removed. - foreach (var portableExecutableReference in project.MetadataReferences.OfType()) + // Loop to find each reference with the given path. It's possible that there might be multiple + // references of the same path; the project system could conceivably add the same reference multiple + // times but with different aliases. It's also possible we might not find the path at all: when we + // receive the file changed event, we aren't checking if the file is still in the workspace at that + // time; it's possible it might have already been removed. + foreach (var oldReference in getReferences(project)) { - if (portableExecutableReference.FilePath == fullFilePath) - { - projectUpdateState = projectUpdateState.WithIncrementalReferenceRemoved(portableExecutableReference); - - var newPortableExecutableReference = - CreateReference_NoLock( - portableExecutableReference.FilePath, - portableExecutableReference.Properties, - SolutionServices); + cancellationToken.ThrowIfCancellationRequested(); - projectUpdateState = projectUpdateState.WithIncrementalReferenceAdded(newPortableExecutableReference); + if (fullFilePath.Equals(getFilePath(oldReference), StringComparison.OrdinalIgnoreCase)) + { + var newReference = createNewReference(solutionServices, oldReference); - var newSolution = solutionChanges.Solution.RemoveMetadataReference(project.Id, portableExecutableReference) - .AddMetadataReference(project.Id, newPortableExecutableReference); + var newSolution = solutionChanges.Solution; + (newSolution, projectUpdateState) = update(newSolution, project.Id, projectUpdateState, oldReference, newReference); solutionChanges.UpdateSolutionForProjectAction(project.Id, newSolution); } } } + return projectUpdateState; }, onAfterUpdateAlways: null).ConfigureAwait(false); } diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectHostInfo.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectHostInfo.cs index 53e50dee4cf74..fc3f0a58ef18a 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectHostInfo.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectHostInfo.cs @@ -11,5 +11,4 @@ namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem; internal record ProjectSystemHostInfo( ImmutableArray> DynamicFileInfoProviders, - IProjectSystemDiagnosticSource DiagnosticSource, IHostDiagnosticAnalyzerProvider HostDiagnosticAnalyzerProvider); diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectOptionsProcessor.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectOptionsProcessor.cs index 9c2059d1006c3..0719507f0daee 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectOptionsProcessor.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectOptionsProcessor.cs @@ -256,7 +256,7 @@ private void RuleSetFile_UpdatedOnDisk(object? sender, EventArgs e) static IEnumerable EnumerateLines( ITemporaryStorageStreamHandle storageHandle) { - using var stream = storageHandle.ReadFromTemporaryStorage(CancellationToken.None); + using var stream = storageHandle.ReadFromTemporaryStorage(); using var reader = new StreamReader(stream); while (reader.ReadLine() is string line) diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/VisualStudioAnalyzer.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/VisualStudioAnalyzer.cs deleted file mode 100644 index a4e2bea760967..0000000000000 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/VisualStudioAnalyzer.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.IO; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace Microsoft.CodeAnalysis.Workspaces.ProjectSystem; - -// TODO: Remove. This is only needed to support Solution Explorer Analyzer node population. -// Analyzers should not be loaded in devenv process (see https://github.com/dotnet/roslyn/issues/43008). -internal sealed class ProjectAnalyzerReference(string fullPath, IAnalyzerAssemblyLoader loader, IProjectSystemDiagnosticSource projectSystemDiagnosticSource, ProjectId projectId, string language) : IDisposable -{ - // these 2 are mutable states that must be guarded under the _gate. - private readonly object _gate = new(); - private AnalyzerReference? _analyzerReference; - private ImmutableArray _analyzerLoadErrors = []; - - public string FullPath { get; } = fullPath; - - public AnalyzerReference GetReference() - { - lock (_gate) - { - if (_analyzerReference == null) - { - // TODO: ensure the file watcher is subscribed - // (tracked by https://devdiv.visualstudio.com/DevDiv/_workitems/edit/661546) - - var analyzerFileReference = new AnalyzerFileReference(FullPath, loader); - analyzerFileReference.AnalyzerLoadFailed += OnAnalyzerLoadError; - _analyzerReference = analyzerFileReference; - } - - return _analyzerReference; - } - } - - private void OnAnalyzerLoadError(object? sender, AnalyzerLoadFailureEventArgs e) - { - var data = projectSystemDiagnosticSource.CreateAnalyzerLoadFailureDiagnostic(e, FullPath, projectId, language); - - lock (_gate) - { - _analyzerLoadErrors = _analyzerLoadErrors.Add(data); - } - } - - public void Dispose() - { - ResetReferenceAndErrors(out var reference, out var loadErrors); - - if (reference is AnalyzerFileReference fileReference) - { - fileReference.AnalyzerLoadFailed -= OnAnalyzerLoadError; - } - } - - private void ResetReferenceAndErrors(out AnalyzerReference? reference, out ImmutableArray loadErrors) - { - lock (_gate) - { - loadErrors = _analyzerLoadErrors; - reference = _analyzerReference; - - _analyzerLoadErrors = []; - _analyzerReference = null; - } - } -} diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/AdditionalDocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/AdditionalDocumentState.cs index 81e61083b694f..a4c4f5fc9c60a 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/AdditionalDocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/AdditionalDocumentState.cs @@ -10,29 +10,42 @@ namespace Microsoft.CodeAnalysis; internal sealed class AdditionalDocumentState : TextDocumentState { - private readonly AdditionalText _additionalText; + public readonly AdditionalText AdditionalText; private AdditionalDocumentState( SolutionServices solutionServices, - IDocumentServiceProvider documentServiceProvider, + IDocumentServiceProvider? documentServiceProvider, DocumentInfo.DocumentAttributes attributes, ITextAndVersionSource textAndVersionSource, LoadTextOptions loadTextOptions) : base(solutionServices, documentServiceProvider, attributes, textAndVersionSource, loadTextOptions) { - _additionalText = new AdditionalTextWithState(this); + AdditionalText = new AdditionalTextWithState(this); } public AdditionalDocumentState( SolutionServices solutionServices, DocumentInfo documentInfo, LoadTextOptions loadTextOptions) - : base(solutionServices, documentInfo, loadTextOptions) + : this(solutionServices, documentInfo.DocumentServiceProvider, documentInfo.Attributes, CreateTextAndVersionSource(solutionServices, documentInfo.TextLoader, documentInfo.FilePath, loadTextOptions), loadTextOptions) { - _additionalText = new AdditionalTextWithState(this); } - public AdditionalText AdditionalText => _additionalText; + protected override TextDocumentState UpdateAttributes(DocumentInfo.DocumentAttributes newAttributes) + => new AdditionalDocumentState( + SolutionServices, + DocumentServiceProvider, + newAttributes, + TextAndVersionSource, + LoadTextOptions); + + protected override TextDocumentState UpdateDocumentServiceProvider(IDocumentServiceProvider? newProvider) + => new AdditionalDocumentState( + SolutionServices, + newProvider, + Attributes, + TextAndVersionSource, + LoadTextOptions); public new AdditionalDocumentState UpdateText(TextLoader loader, PreservationMode mode) => (AdditionalDocumentState)base.UpdateText(loader, mode); @@ -46,8 +59,8 @@ public AdditionalDocumentState( protected override TextDocumentState UpdateText(ITextAndVersionSource newTextSource, PreservationMode mode, bool incremental) { return new AdditionalDocumentState( - this.solutionServices, - this.Services, + this.SolutionServices, + this.DocumentServiceProvider, this.Attributes, newTextSource, this.LoadTextOptions); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/AnalyzerConfigDocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/AnalyzerConfigDocumentState.cs index da0d0ef11002a..c0285cdc8b8dd 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/AnalyzerConfigDocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/AnalyzerConfigDocumentState.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; @@ -14,38 +12,50 @@ namespace Microsoft.CodeAnalysis; internal sealed class AnalyzerConfigDocumentState : TextDocumentState { - private readonly AsyncLazy _analyzerConfigValueSource; + private readonly AsyncLazy _lazyAnalyzerConfig; private AnalyzerConfigDocumentState( SolutionServices solutionServices, - IDocumentServiceProvider documentServiceProvider, + IDocumentServiceProvider? documentServiceProvider, DocumentInfo.DocumentAttributes attributes, ITextAndVersionSource textAndVersionSource, - LoadTextOptions loadTextOptions) + LoadTextOptions loadTextOptions, + AsyncLazy? lazyAnalyzerConfig = null) : base(solutionServices, documentServiceProvider, attributes, textAndVersionSource, loadTextOptions) { - _analyzerConfigValueSource = CreateAnalyzerConfigValueSource(); + _lazyAnalyzerConfig = lazyAnalyzerConfig ?? AsyncLazy.Create( + asynchronousComputeFunction: static async (self, cancellationToken) => AnalyzerConfig.Parse(await self.GetTextAsync(cancellationToken).ConfigureAwait(false), self.FilePath), + synchronousComputeFunction: static (self, cancellationToken) => AnalyzerConfig.Parse(self.GetTextSynchronously(cancellationToken), self.FilePath), + arg: this); } public AnalyzerConfigDocumentState( SolutionServices solutionServices, DocumentInfo documentInfo, LoadTextOptions loadTextOptions) - : base(solutionServices, documentInfo, loadTextOptions) + : this(solutionServices, documentInfo.DocumentServiceProvider, documentInfo.Attributes, CreateTextAndVersionSource(solutionServices, documentInfo.TextLoader, documentInfo.FilePath, loadTextOptions), loadTextOptions) { - _analyzerConfigValueSource = CreateAnalyzerConfigValueSource(); } - private AsyncLazy CreateAnalyzerConfigValueSource() - { - return AsyncLazy.Create( - asynchronousComputeFunction: static async (self, cancellationToken) => AnalyzerConfig.Parse(await self.GetTextAsync(cancellationToken).ConfigureAwait(false), self.FilePath), - synchronousComputeFunction: static (self, cancellationToken) => AnalyzerConfig.Parse(self.GetTextSynchronously(cancellationToken), self.FilePath), - arg: this); - } + protected override TextDocumentState UpdateAttributes(DocumentInfo.DocumentAttributes newAttributes) + => new AnalyzerConfigDocumentState( + SolutionServices, + DocumentServiceProvider, + newAttributes, + TextAndVersionSource, + LoadTextOptions, + // Reuse parsed config unless the path changed: + Attributes.FilePath == newAttributes.FilePath ? _lazyAnalyzerConfig : null); - public AnalyzerConfig GetAnalyzerConfig(CancellationToken cancellationToken) => _analyzerConfigValueSource.GetValue(cancellationToken); - public Task GetAnalyzerConfigAsync(CancellationToken cancellationToken) => _analyzerConfigValueSource.GetValueAsync(cancellationToken); + protected override TextDocumentState UpdateDocumentServiceProvider(IDocumentServiceProvider? newProvider) + => new AnalyzerConfigDocumentState( + SolutionServices, + DocumentServiceProvider, + Attributes, + TextAndVersionSource, + LoadTextOptions, + // Reuse parsed config: + _lazyAnalyzerConfig); public new AnalyzerConfigDocumentState UpdateText(TextLoader loader, PreservationMode mode) => (AnalyzerConfigDocumentState)base.UpdateText(loader, mode); @@ -59,10 +69,16 @@ private AsyncLazy CreateAnalyzerConfigValueSource() protected override TextDocumentState UpdateText(ITextAndVersionSource newTextSource, PreservationMode mode, bool incremental) { return new AnalyzerConfigDocumentState( - this.solutionServices, - this.Services, + this.SolutionServices, + this.DocumentServiceProvider, this.Attributes, newTextSource, this.LoadTextOptions); } + + public AnalyzerConfig GetAnalyzerConfig(CancellationToken cancellationToken) + => _lazyAnalyzerConfig.GetValue(cancellationToken); + + public Task GetAnalyzerConfigAsync(CancellationToken cancellationToken) + => _lazyAnalyzerConfig.GetValueAsync(cancellationToken); } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs index f425a52edcacb..44ea0b096f45d 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs @@ -60,7 +60,7 @@ public static Checksum From(ReadOnlySpan checksum) public string ToBase64String() { -#if NETCOREAPP +#if NET Span bytes = stackalloc byte[HashSize]; this.WriteTo(bytes); return Convert.ToBase64String(bytes); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs index 285e12ba49633..8579fba2f1ba8 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs @@ -29,10 +29,10 @@ internal partial class DocumentState : TextDocumentState // properties inherited from the containing project: public LanguageServices LanguageServices { get; } - private readonly ParseOptions? _options; + public ParseOptions? ParseOptions { get; } // null if the document doesn't support syntax trees: - private readonly ITreeAndVersionSource? _treeSource; + public ITreeAndVersionSource? TreeSource { get; } private ImmutableArray _contentHash; @@ -40,62 +40,63 @@ protected DocumentState( LanguageServices languageServices, IDocumentServiceProvider? documentServiceProvider, DocumentInfo.DocumentAttributes attributes, - ParseOptions? options, ITextAndVersionSource textSource, LoadTextOptions loadTextOptions, + ParseOptions? options, ITreeAndVersionSource? treeSource) : base(languageServices.SolutionServices, documentServiceProvider, attributes, textSource, loadTextOptions) { - Contract.ThrowIfFalse(_options is null == _treeSource is null); + Contract.ThrowIfFalse(ParseOptions is null == TreeSource is null); LanguageServices = languageServices; - _options = options; - _treeSource = treeSource; + ParseOptions = options; + TreeSource = treeSource; } - public DocumentState( + public static DocumentState Create( LanguageServices languageServices, DocumentInfo info, ParseOptions? options, LoadTextOptions loadTextOptions) - : base(languageServices.SolutionServices, info, loadTextOptions) { - LanguageServices = languageServices; - _options = options; + var textSource = CreateTextAndVersionSource(languageServices.SolutionServices, info.TextLoader, info.FilePath, loadTextOptions); // If this is document that doesn't support syntax, then don't even bother holding // onto any tree source. It will never be used to get a tree, and can only hurt us // by possibly holding onto data that might cause a slow memory leak. + ITreeAndVersionSource? treeSource; if (languageServices.GetService() == null) { - _treeSource = null; + treeSource = null; } else { Contract.ThrowIfNull(options); - _treeSource = CreateLazyFullyParsedTree( - TextAndVersionSource, - LoadTextOptions, + treeSource = CreateLazyFullyParsedTree( + textSource, + loadTextOptions, info.Attributes.SyntaxTreeFilePath, options, languageServices); } - } - public ITreeAndVersionSource? TreeSource => _treeSource; + return new DocumentState( + languageServices, + info.DocumentServiceProvider, + info.Attributes, + textSource, + loadTextOptions, + options, + treeSource); + } - [MemberNotNullWhen(true, nameof(_treeSource))] [MemberNotNullWhen(true, nameof(TreeSource))] - [MemberNotNullWhen(true, nameof(_options))] [MemberNotNullWhen(true, nameof(ParseOptions))] internal bool SupportsSyntaxTree - => _treeSource != null; - - public ParseOptions? ParseOptions - => _options; + => TreeSource != null; public SourceCodeKind SourceCodeKind - => ParseOptions == null ? Attributes.SourceCodeKind : ParseOptions.Kind; + => ParseOptions?.Kind ?? Attributes.SourceCodeKind; public bool IsGenerated => Attributes.IsGenerated; @@ -293,7 +294,7 @@ private static bool TopLevelChanged(SyntaxTree oldTree, SourceText oldText, Synt public bool HasContentChanged(DocumentState oldState) { - return oldState._treeSource != _treeSource + return oldState.TreeSource != TreeSource || HasTextChanged(oldState, ignoreUnchangeableDocument: false); } @@ -322,33 +323,20 @@ public DocumentState UpdateChecksumAlgorithm(SourceHashAlgorithm checksumAlgorit TextAndVersionSource, newLoadTextOptions, Attributes.SyntaxTreeFilePath, - _options, + ParseOptions, LanguageServices) : null; return new DocumentState( LanguageServices, - Services, + DocumentServiceProvider, Attributes, - _options, TextAndVersionSource, newLoadTextOptions, + ParseOptions, newTreeSource); } - public DocumentState UpdateParseOptions(ParseOptions options, bool onlyPreprocessorDirectiveChange) - { - var originalSourceKind = this.SourceCodeKind; - - var newState = this.SetParseOptions(options, onlyPreprocessorDirectiveChange); - if (newState.SourceCodeKind != originalSourceKind) - { - newState = newState.UpdateSourceCodeKind(originalSourceKind); - } - - return newState; - } - - private DocumentState SetParseOptions(ParseOptions options, bool onlyPreprocessorDirectiveChange) + public DocumentState UpdateParseOptionsAndSourceCodeKind(ParseOptions options, bool onlyPreprocessorDirectiveChange) { Contract.ThrowIfFalse(SupportsSyntaxTree); @@ -360,7 +348,7 @@ private DocumentState SetParseOptions(ParseOptions options, bool onlyPreprocesso // We only need to care about `#if` directives as those are the only sorts of directives that can affect how // a tree is parsed. if (onlyPreprocessorDirectiveChange && - _treeSource.TryGetValue(out var existingTreeAndVersion)) + TreeSource.TryGetValue(out var existingTreeAndVersion)) { var existingTree = existingTreeAndVersion.Tree; @@ -370,7 +358,7 @@ private DocumentState SetParseOptions(ParseOptions options, bool onlyPreprocesso if (existingTree.TryGetRoot(out var existingRoot) && !existingRoot.ContainsDirective(syntaxKinds.IfDirectiveTrivia)) { var treeFactory = LanguageServices.GetRequiredService(); - newTree = treeFactory.CreateSyntaxTree(Attributes.SyntaxTreeFilePath, options, existingTree.Encoding, LoadTextOptions.ChecksumAlgorithm, existingRoot); + newTree = treeFactory.CreateSyntaxTree(Attributes.SyntaxTreeFilePath, options, text: null, existingTree.Encoding, LoadTextOptions.ChecksumAlgorithm, existingRoot); } if (newTree is not null) @@ -387,37 +375,32 @@ private DocumentState SetParseOptions(ParseOptions options, bool onlyPreprocesso return new DocumentState( LanguageServices, - Services, + DocumentServiceProvider, Attributes.With(sourceCodeKind: options.Kind), - options, TextAndVersionSource, LoadTextOptions, + options, newTreeSource); } public DocumentState UpdateSourceCodeKind(SourceCodeKind kind) { - if (this.ParseOptions == null || kind == this.SourceCodeKind) + if (kind == SourceCodeKind) { return this; } - return this.SetParseOptions(this.ParseOptions.WithKind(kind), onlyPreprocessorDirectiveChange: false); - } - - public DocumentState UpdateName(string name) - => UpdateAttributes(Attributes.With(name: name)); - - public DocumentState UpdateFilePath(string? path) - => UpdateAttributes(Attributes.With(filePath: path)); + if (ParseOptions != null) + { + return UpdateParseOptionsAndSourceCodeKind(ParseOptions.WithKind(kind), onlyPreprocessorDirectiveChange: false); + } - public DocumentState UpdateFolders(IReadOnlyList folders) - => UpdateAttributes(Attributes.With(folders: folders)); + return WithAttributes(Attributes.With(sourceCodeKind: kind)); + } - private DocumentState UpdateAttributes(DocumentInfo.DocumentAttributes newAttributes) + protected override TextDocumentState UpdateAttributes(DocumentInfo.DocumentAttributes newAttributes) { - Debug.Assert(newAttributes != Attributes); - + Contract.ThrowIfTrue(ReferenceEquals(newAttributes, Attributes)); ITreeAndVersionSource? newTreeSource; if (newAttributes.SyntaxTreeFilePath != Attributes.SyntaxTreeFilePath) @@ -429,24 +412,37 @@ private DocumentState UpdateAttributes(DocumentInfo.DocumentAttributes newAttrib TextAndVersionSource, LoadTextOptions, newAttributes.SyntaxTreeFilePath, - _options, + ParseOptions, LanguageServices) : null; } else { - newTreeSource = _treeSource; + newTreeSource = TreeSource; } return new DocumentState( LanguageServices, - Services, + DocumentServiceProvider, newAttributes, - _options, TextAndVersionSource, LoadTextOptions, + ParseOptions, newTreeSource); } + protected override TextDocumentState UpdateDocumentServiceProvider(IDocumentServiceProvider? newProvider) + => new DocumentState( + LanguageServices, + newProvider, + Attributes, + TextAndVersionSource, + LoadTextOptions, + ParseOptions, + TreeSource); + + public new DocumentState WithAttributes(DocumentInfo.DocumentAttributes newAttributes) + => (DocumentState)base.WithAttributes(newAttributes); + public new DocumentState UpdateText(SourceText newText, PreservationMode mode) => (DocumentState)base.UpdateText(newText, mode); @@ -466,7 +462,7 @@ protected override TextDocumentState UpdateText(ITextAndVersionSource newTextSou } else if (incremental) { - newTreeSource = CreateLazyIncrementallyParsedTree(_treeSource, newTextSource, LoadTextOptions); + newTreeSource = CreateLazyIncrementallyParsedTree(TreeSource, newTextSource, LoadTextOptions); } else { @@ -474,18 +470,18 @@ protected override TextDocumentState UpdateText(ITextAndVersionSource newTextSou newTextSource, LoadTextOptions, Attributes.SyntaxTreeFilePath, - _options, + ParseOptions, LanguageServices, mode); // TODO: understand why the mode is given here. If we're preserving text by identity, why also preserve the tree? } return new DocumentState( LanguageServices, - Services, + DocumentServiceProvider, Attributes, - _options, textSource: newTextSource, LoadTextOptions, + ParseOptions, treeSource: newTreeSource); } @@ -519,16 +515,16 @@ internal DocumentState UpdateTree(SyntaxNode newRoot, PreservationMode mode) var syntaxTreeFactory = LanguageServices.GetRequiredService(); - Contract.ThrowIfNull(_options); - var (text, treeAndVersion) = CreateTreeWithLazyText(newRoot, newTextVersion, newTreeVersion, encoding, LoadTextOptions.ChecksumAlgorithm, Attributes, _options, syntaxTreeFactory); + Contract.ThrowIfNull(ParseOptions); + var (text, treeAndVersion) = CreateTreeWithLazyText(newRoot, newTextVersion, newTreeVersion, encoding, LoadTextOptions.ChecksumAlgorithm, Attributes, ParseOptions, syntaxTreeFactory); return new DocumentState( LanguageServices, - Services, + DocumentServiceProvider, Attributes, - _options, textSource: text, LoadTextOptions, + ParseOptions, treeSource: SimpleTreeAndVersionSource.Create(treeAndVersion)); // use static method so we don't capture references to this @@ -542,7 +538,7 @@ internal DocumentState UpdateTree(SyntaxNode newRoot, PreservationMode mode) ParseOptions options, ISyntaxTreeFactoryService factory) { - var tree = factory.CreateSyntaxTree(attributes.SyntaxTreeFilePath, options, encoding, checksumAlgorithm, newRoot); + var tree = factory.CreateSyntaxTree(attributes.SyntaxTreeFilePath, options, text: null, encoding, checksumAlgorithm, newRoot); // its okay to use a strong cached AsyncLazy here because the compiler layer SyntaxTree will also keep the text alive once its built. var lazyTextAndVersion = new TreeTextSource( @@ -558,14 +554,14 @@ internal DocumentState UpdateTree(SyntaxNode newRoot, PreservationMode mode) private VersionStamp GetNewTreeVersionForUpdatedTree(SyntaxNode newRoot, VersionStamp newTextVersion, PreservationMode mode) { - RoslynDebug.Assert(_treeSource != null); + RoslynDebug.Assert(TreeSource != null); if (mode != PreservationMode.PreserveIdentity) { return newTextVersion; } - if (!_treeSource.TryGetValue(out var oldTreeAndVersion) || !oldTreeAndVersion!.Tree.TryGetRoot(out var oldRoot)) + if (!TreeSource.TryGetValue(out var oldTreeAndVersion) || !oldTreeAndVersion!.Tree.TryGetRoot(out var oldRoot)) { return newTextVersion; } @@ -590,7 +586,7 @@ private VersionStamp GetNewerVersion() return textAndVersion!.Version.GetNewerVersion(); } - if (_treeSource != null && _treeSource.TryGetValue(out var treeAndVersion) && treeAndVersion != null) + if (TreeSource != null && TreeSource.TryGetValue(out var treeAndVersion) && treeAndVersion != null) { return treeAndVersion.Version.GetNewerVersion(); } @@ -601,7 +597,7 @@ private VersionStamp GetNewerVersion() public bool TryGetSyntaxTree([NotNullWhen(returnValue: true)] out SyntaxTree? syntaxTree) { syntaxTree = null; - if (_treeSource != null && _treeSource.TryGetValue(out var treeAndVersion) && treeAndVersion != null) + if (TreeSource != null && TreeSource.TryGetValue(out var treeAndVersion) && treeAndVersion != null) { syntaxTree = treeAndVersion.Tree; BindSyntaxTreeToId(syntaxTree, Id); @@ -615,9 +611,9 @@ public bool TryGetSyntaxTree([NotNullWhen(returnValue: true)] out SyntaxTree? sy public async ValueTask GetSyntaxTreeAsync(CancellationToken cancellationToken) { // operation should only be performed on documents that support syntax trees - RoslynDebug.Assert(_treeSource != null); + RoslynDebug.Assert(TreeSource != null); - var treeAndVersion = await _treeSource.GetValueAsync(cancellationToken).ConfigureAwait(false); + var treeAndVersion = await TreeSource.GetValueAsync(cancellationToken).ConfigureAwait(false); // make sure there is an association between this tree and this doc id before handing it out BindSyntaxTreeToId(treeAndVersion.Tree, this.Id); @@ -627,9 +623,9 @@ public async ValueTask GetSyntaxTreeAsync(CancellationToken cancella internal SyntaxTree GetSyntaxTree(CancellationToken cancellationToken) { // operation should only be performed on documents that support syntax trees - RoslynDebug.Assert(_treeSource != null); + RoslynDebug.Assert(TreeSource != null); - var treeAndVersion = _treeSource.GetValue(cancellationToken); + var treeAndVersion = TreeSource.GetValue(cancellationToken); // make sure there is an association between this tree and this doc id before handing it out BindSyntaxTreeToId(treeAndVersion.Tree, this.Id); @@ -638,7 +634,7 @@ internal SyntaxTree GetSyntaxTree(CancellationToken cancellationToken) public bool TryGetTopLevelChangeTextVersion(out VersionStamp version) { - if (_treeSource != null && _treeSource.TryGetValue(out var treeAndVersion) && treeAndVersion != null) + if (TreeSource != null && TreeSource.TryGetValue(out var treeAndVersion) && treeAndVersion != null) { version = treeAndVersion.Version; return true; @@ -652,17 +648,17 @@ public bool TryGetTopLevelChangeTextVersion(out VersionStamp version) public override async ValueTask GetTopLevelChangeTextVersionAsync(CancellationToken cancellationToken) { - if (_treeSource == null) + if (TreeSource == null) { return await GetTextVersionAsync(cancellationToken).ConfigureAwait(false); } - if (_treeSource.TryGetValue(out var treeAndVersion) && treeAndVersion != null) + if (TreeSource.TryGetValue(out var treeAndVersion) && treeAndVersion != null) { return treeAndVersion.Version; } - treeAndVersion = await _treeSource.GetValueAsync(cancellationToken).ConfigureAwait(false); + treeAndVersion = await TreeSource.GetValueAsync(cancellationToken).ConfigureAwait(false); return treeAndVersion.Version; } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState_LinkedFileReuse.cs b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState_LinkedFileReuse.cs index 8c481c1b4a3be..0718a34780b21 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState_LinkedFileReuse.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState_LinkedFileReuse.cs @@ -51,11 +51,11 @@ public DocumentState UpdateTextAndTreeContents( { return new DocumentState( LanguageServices, - Services, + DocumentServiceProvider, Attributes, - _options, siblingTextSource, LoadTextOptions, + ParseOptions, treeSource: null); } @@ -77,7 +77,7 @@ public DocumentState UpdateTextAndTreeContents( // Defer to static helper to make sure we don't accidentally capture anything else we don't want off of 'this' // (like "this.TreeSource"). return UpdateTextAndTreeContentsWorker( - this.Attributes, this.LanguageServices, this.Services, this.LoadTextOptions, this.ParseOptions, + this.Attributes, this.LanguageServices, this.DocumentServiceProvider, this.LoadTextOptions, this.ParseOptions, originalTreeSource, siblingTextSource, siblingTreeSource, forceEvenIfTreesWouldDiffer); } @@ -106,7 +106,7 @@ private static DocumentState UpdateTextAndTreeContentsWorker( var newTreeSource = new LinkedFileReuseTreeAndVersionSource(originalTreeSource, lazyComputation); return new DocumentState( - languageServices, services, attributes, parseOptions, siblingTextSource, loadTextOptions, newTreeSource); + languageServices, services, attributes, siblingTextSource, loadTextOptions, parseOptions, newTreeSource); static bool TryReuseSiblingRoot( string filePath, @@ -133,9 +133,13 @@ static bool TryReuseSiblingRoot( // with our own data (*except* for the new root). However, we think it's safe as the encoding really is // a property of the file, and that should stay the same even if linked into multiple projects. + // Attempt to obtain, and subsequently reuse, the SourceText from the sibling tree. + siblingTree.TryGetText(out var lazyText); + var newTree = treeFactory.CreateSyntaxTree( filePath, parseOptions, + lazyText, siblingTree.Encoding, loadTextOptions.ChecksumAlgorithm, siblingRoot); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/IChecksummedObject.cs b/src/Workspaces/Core/Portable/Workspace/Solution/IChecksummedObject.cs deleted file mode 100644 index 923e68f9acda3..0000000000000 --- a/src/Workspaces/Core/Portable/Workspace/Solution/IChecksummedObject.cs +++ /dev/null @@ -1,15 +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 - -namespace Microsoft.CodeAnalysis; - -/// -/// Indicates whether a type has checksum or not -/// -internal interface IChecksummedObject -{ - Checksum Checksum { get; } -} diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs index c0ff46b64c02e..b5ec662946e33 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Project.cs @@ -26,8 +26,6 @@ namespace Microsoft.CodeAnalysis; [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] public partial class Project { - private readonly Solution _solution; - private readonly ProjectState _projectState; private ImmutableDictionary _idToDocumentMap = ImmutableDictionary.Empty; private ImmutableDictionary _idToSourceGeneratedDocumentMap = ImmutableDictionary.Empty; private ImmutableDictionary _idToAdditionalDocumentMap = ImmutableDictionary.Empty; @@ -38,42 +36,42 @@ internal Project(Solution solution, ProjectState projectState) Contract.ThrowIfNull(solution); Contract.ThrowIfNull(projectState); - _solution = solution; - _projectState = projectState; + Solution = solution; + State = projectState; } - internal ProjectState State => _projectState; + internal ProjectState State { get; } /// /// The solution this project is part of. /// - public Solution Solution => _solution; + public Solution Solution { get; } /// /// The ID of the project. Multiple instances may share the same ID. However, only /// one project may have this ID in any given solution. /// - public ProjectId Id => _projectState.Id; + public ProjectId Id => State.Id; /// /// The path to the project file or null if there is no project file. /// - public string? FilePath => _projectState.FilePath; + public string? FilePath => State.FilePath; /// /// The path to the output file, or null if it is not known. /// - public string? OutputFilePath => _projectState.OutputFilePath; + public string? OutputFilePath => State.OutputFilePath; /// /// The path to the reference assembly output file, or null if it is not known. /// - public string? OutputRefFilePath => _projectState.OutputRefFilePath; + public string? OutputRefFilePath => State.OutputRefFilePath; /// /// Compilation output file paths. /// - public CompilationOutputInfo CompilationOutputInfo => _projectState.CompilationOutputInfo; + public CompilationOutputInfo CompilationOutputInfo => State.CompilationOutputInfo; /// /// The default namespace of the project ("" if not defined, which means global namespace), @@ -86,7 +84,7 @@ internal Project(Solution solution, ProjectState projectState) /// In the future, we might consider officially exposing "default namespace" for VB project /// (e.g. through a "defaultnamespace" msbuild property) /// - public string? DefaultNamespace => _projectState.DefaultNamespace; + public string? DefaultNamespace => State.DefaultNamespace; /// /// if this supports providing data through the @@ -101,90 +99,90 @@ internal Project(Solution solution, ProjectState projectState) /// [Obsolete($"Use {nameof(Services)} instead.")] #pragma warning disable CS0618 // Member is obsolete -- shouldn't be reported here https://github.com/dotnet/roslyn/issues/66409 - public HostLanguageServices LanguageServices => _projectState.LanguageServices.HostLanguageServices; + public HostLanguageServices LanguageServices => State.LanguageServices.HostLanguageServices; #pragma warning restore /// /// Immutable snapshot of language services from the host environment associated with this project's language. /// Use this over when possible. /// - public LanguageServices Services => _projectState.LanguageServices; + public LanguageServices Services => State.LanguageServices; /// /// The language associated with the project. /// - public string Language => _projectState.Language; + public string Language => State.Language; /// /// The name of the assembly this project represents. /// - public string AssemblyName => _projectState.AssemblyName; + public string AssemblyName => State.AssemblyName; /// /// The name of the project. This may be different than the assembly name. /// - public string Name => _projectState.Name; + public string Name => State.Name; /// /// The list of all other metadata sources (assemblies) that this project references. /// - public IReadOnlyList MetadataReferences => _projectState.MetadataReferences; + public IReadOnlyList MetadataReferences => State.MetadataReferences; /// /// The list of all other projects within the same solution that this project references. /// - public IEnumerable ProjectReferences => _projectState.ProjectReferences.Where(pr => this.Solution.ContainsProject(pr.ProjectId)); + public IEnumerable ProjectReferences => State.ProjectReferences.Where(pr => this.Solution.ContainsProject(pr.ProjectId)); /// /// The list of all other projects that this project references, including projects that /// are not part of the solution. /// - public IReadOnlyList AllProjectReferences => _projectState.ProjectReferences; + public IReadOnlyList AllProjectReferences => State.ProjectReferences; /// /// The list of all the diagnostic analyzer references for this project. /// - public IReadOnlyList AnalyzerReferences => _projectState.AnalyzerReferences; + public IReadOnlyList AnalyzerReferences => State.AnalyzerReferences; /// /// The options used by analyzers for this project. /// - public AnalyzerOptions AnalyzerOptions => _projectState.AnalyzerOptions; + public AnalyzerOptions AnalyzerOptions => State.AnalyzerOptions; /// /// The options used when building the compilation for this project. /// - public CompilationOptions? CompilationOptions => _projectState.CompilationOptions; + public CompilationOptions? CompilationOptions => State.CompilationOptions; /// /// The options used when parsing documents for this project. /// - public ParseOptions? ParseOptions => _projectState.ParseOptions; + public ParseOptions? ParseOptions => State.ParseOptions; /// /// Returns true if this is a submission project. /// - public bool IsSubmission => _projectState.IsSubmission; + public bool IsSubmission => State.IsSubmission; /// /// True if the project has any documents. /// - public bool HasDocuments => !_projectState.DocumentStates.IsEmpty; + public bool HasDocuments => !State.DocumentStates.IsEmpty; /// /// All the document IDs associated with this project. /// - public IReadOnlyList DocumentIds => _projectState.DocumentStates.Ids; + public IReadOnlyList DocumentIds => State.DocumentStates.Ids; /// /// All the additional document IDs associated with this project. /// - public IReadOnlyList AdditionalDocumentIds => _projectState.AdditionalDocumentStates.Ids; + public IReadOnlyList AdditionalDocumentIds => State.AdditionalDocumentStates.Ids; /// /// All the additional document IDs associated with this project. /// - internal IReadOnlyList AnalyzerConfigDocumentIds => _projectState.AnalyzerConfigDocumentStates.Ids; + internal IReadOnlyList AnalyzerConfigDocumentIds => State.AnalyzerConfigDocumentStates.Ids; /// /// All the regular documents associated with this project. Documents produced from source generators are returned by @@ -206,31 +204,31 @@ internal Project(Solution solution, ProjectState projectState) /// True if the project contains a document with the specified ID. /// public bool ContainsDocument(DocumentId documentId) - => _projectState.DocumentStates.Contains(documentId); + => State.DocumentStates.Contains(documentId); /// /// True if the project contains an additional document with the specified ID. /// public bool ContainsAdditionalDocument(DocumentId documentId) - => _projectState.AdditionalDocumentStates.Contains(documentId); + => State.AdditionalDocumentStates.Contains(documentId); /// /// True if the project contains an with the specified ID. /// public bool ContainsAnalyzerConfigDocument(DocumentId documentId) - => _projectState.AnalyzerConfigDocumentStates.Contains(documentId); + => State.AnalyzerConfigDocumentStates.Contains(documentId); /// /// Get the documentId in this project with the specified syntax tree. /// public DocumentId? GetDocumentId(SyntaxTree? syntaxTree) - => _solution.GetDocumentId(syntaxTree, this.Id); + => Solution.GetDocumentId(syntaxTree, this.Id); /// /// Get the document in this project with the specified syntax tree. /// public Document? GetDocument(SyntaxTree? syntaxTree) - => _solution.GetDocument(syntaxTree, this.Id); + => Solution.GetDocument(syntaxTree, this.Id); /// /// Get the document in this project with the specified document Id. @@ -281,7 +279,7 @@ public bool ContainsAnalyzerConfigDocument(DocumentId documentId) /// public async ValueTask> GetSourceGeneratedDocumentsAsync(CancellationToken cancellationToken = default) { - var generatedDocumentStates = await _solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(this.State, cancellationToken).ConfigureAwait(false); + var generatedDocumentStates = await Solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(this.State, cancellationToken).ConfigureAwait(false); // return an iterator to avoid eagerly allocating all the document instances return generatedDocumentStates.States.Values.Select(state => @@ -313,7 +311,7 @@ internal async IAsyncEnumerable GetAllRegularAndSourceGeneratedDocumen return sourceGeneratedDocument; // We'll have to run generators if we haven't already and now try to find it. - var generatedDocumentStates = await _solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(State, cancellationToken).ConfigureAwait(false); + var generatedDocumentStates = await Solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(State, cancellationToken).ConfigureAwait(false); var generatedDocumentState = generatedDocumentStates.GetState(documentId); if (generatedDocumentState is null) return null; @@ -349,7 +347,7 @@ internal SourceGeneratedDocument GetOrCreateSourceGeneratedDocument(SourceGenera // Trickier case now: it's possible we generated this, but we don't actually have the SourceGeneratedDocument for it, so let's go // try to fetch the state. - var documentState = _solution.CompilationState.TryGetSourceGeneratedDocumentStateForAlreadyGeneratedId(documentId); + var documentState = Solution.CompilationState.TryGetSourceGeneratedDocumentStateForAlreadyGeneratedId(documentId); if (documentState == null) return null; @@ -358,12 +356,12 @@ internal SourceGeneratedDocument GetOrCreateSourceGeneratedDocument(SourceGenera internal ValueTask> GetSourceGeneratorDiagnosticsAsync(CancellationToken cancellationToken) { - return _solution.CompilationState.GetSourceGeneratorDiagnosticsAsync(this.State, cancellationToken); + return Solution.CompilationState.GetSourceGeneratorDiagnosticsAsync(this.State, cancellationToken); } internal ValueTask GetSourceGeneratorRunResultAsync(CancellationToken cancellationToken) { - return _solution.CompilationState.GetSourceGeneratorRunResultAsync(this.State, cancellationToken); + return Solution.CompilationState.GetSourceGeneratorRunResultAsync(this.State, cancellationToken); } internal Task ContainsSymbolsWithNameAsync( @@ -461,13 +459,13 @@ private async Task ContainsAsync(Func> predicateAsync } private static readonly Func s_tryCreateDocumentFunction = - (documentId, project) => project._projectState.DocumentStates.TryGetState(documentId, out var state) ? new Document(project, state) : null; + (documentId, project) => project.State.DocumentStates.TryGetState(documentId, out var state) ? new Document(project, state) : null; private static readonly Func s_tryCreateAdditionalDocumentFunction = - (documentId, project) => project._projectState.AdditionalDocumentStates.TryGetState(documentId, out var state) ? new AdditionalDocument(project, state) : null; + (documentId, project) => project.State.AdditionalDocumentStates.TryGetState(documentId, out var state) ? new AdditionalDocument(project, state) : null; private static readonly Func s_tryCreateAnalyzerConfigDocumentFunction = - (documentId, project) => project._projectState.AnalyzerConfigDocumentStates.TryGetState(documentId, out var state) ? new AnalyzerConfigDocument(project, state) : null; + (documentId, project) => project.State.AnalyzerConfigDocumentStates.TryGetState(documentId, out var state) ? new AnalyzerConfigDocument(project, state) : null; private static readonly Func s_createSourceGeneratedDocumentFunction = (documentId, stateAndProject) => new SourceGeneratedDocument(stateAndProject.project, stateAndProject.state); @@ -478,7 +476,7 @@ private async Task ContainsAsync(Func> predicateAsync /// or create a new one otherwise. /// public bool TryGetCompilation([NotNullWhen(returnValue: true)] out Compilation? compilation) - => _solution.CompilationState.TryGetCompilation(this.Id, out compilation); + => Solution.CompilationState.TryGetCompilation(this.Id, out compilation); /// /// Get the for this project asynchronously. @@ -489,14 +487,14 @@ public bool TryGetCompilation([NotNullWhen(returnValue: true)] out Compilation? /// return the same value if called multiple times. /// public Task GetCompilationAsync(CancellationToken cancellationToken = default) - => _solution.CompilationState.GetCompilationAsync(_projectState, cancellationToken); + => Solution.CompilationState.GetCompilationAsync(State, cancellationToken); /// /// Determines if the compilation returned by and all its referenced compilation are from fully loaded projects. /// // TODO: make this public internal Task HasSuccessfullyLoadedAsync(CancellationToken cancellationToken) - => _solution.CompilationState.HasSuccessfullyLoadedAsync(_projectState, cancellationToken); + => Solution.CompilationState.HasSuccessfullyLoadedAsync(State, cancellationToken); /// /// Gets an object that lists the added, changed and removed documents between this project and the specified project. @@ -514,33 +512,33 @@ public ProjectChanges GetChanges(Project oldProject) /// /// The project version. This equates to the version of the project file. /// - public VersionStamp Version => _projectState.Version; + public VersionStamp Version => State.Version; /// /// The version of the most recently modified document. /// public Task GetLatestDocumentVersionAsync(CancellationToken cancellationToken = default) - => _projectState.GetLatestDocumentVersionAsync(cancellationToken); + => State.GetLatestDocumentVersionAsync(cancellationToken); /// /// The most recent version of the project, its documents and all dependent projects and documents. /// public Task GetDependentVersionAsync(CancellationToken cancellationToken = default) - => _solution.CompilationState.GetDependentVersionAsync(this.Id, cancellationToken); + => Solution.CompilationState.GetDependentVersionAsync(this.Id, cancellationToken); /// /// The semantic version of this project including the semantics of referenced projects. /// This version changes whenever the consumable declarations of this project and/or projects it depends on change. /// public Task GetDependentSemanticVersionAsync(CancellationToken cancellationToken = default) - => _solution.CompilationState.GetDependentSemanticVersionAsync(this.Id, cancellationToken); + => Solution.CompilationState.GetDependentSemanticVersionAsync(this.Id, cancellationToken); /// /// The semantic version of this project not including the semantics of referenced projects. /// This version changes only when the consumable declarations of this project change. /// public Task GetSemanticVersionAsync(CancellationToken cancellationToken = default) - => _projectState.GetSemanticVersionAsync(cancellationToken); + => State.GetSemanticVersionAsync(cancellationToken); /// /// Calculates a checksum that contains a project's checksum along with a checksum for each of the project's @@ -568,112 +566,119 @@ public Task GetSemanticVersionAsync(CancellationToken cancellation /// /// internal Task GetDependentChecksumAsync(CancellationToken cancellationToken) - => _solution.CompilationState.GetDependentChecksumAsync(this.Id, cancellationToken); + => Solution.CompilationState.GetDependentChecksumAsync(this.Id, cancellationToken); /// /// Creates a new instance of this project updated to have the new assembly name. /// public Project WithAssemblyName(string assemblyName) - => this.Solution.WithProjectAssemblyName(this.Id, assemblyName).GetProject(this.Id)!; + => this.Solution.WithProjectAssemblyName(this.Id, assemblyName).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to have the new default namespace. /// public Project WithDefaultNamespace(string defaultNamespace) - => this.Solution.WithProjectDefaultNamespace(this.Id, defaultNamespace).GetProject(this.Id)!; + => this.Solution.WithProjectDefaultNamespace(this.Id, defaultNamespace).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to have the specified compilation options. /// public Project WithCompilationOptions(CompilationOptions options) - => this.Solution.WithProjectCompilationOptions(this.Id, options).GetProject(this.Id)!; + => this.Solution.WithProjectCompilationOptions(this.Id, options).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to have the specified parse options. /// public Project WithParseOptions(ParseOptions options) - => this.Solution.WithProjectParseOptions(this.Id, options).GetProject(this.Id)!; + => this.Solution.WithProjectParseOptions(this.Id, options).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to include the specified project reference /// in addition to already existing ones. /// public Project AddProjectReference(ProjectReference projectReference) - => this.Solution.AddProjectReference(this.Id, projectReference).GetProject(this.Id)!; + => this.Solution.AddProjectReference(this.Id, projectReference).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to include the specified project references /// in addition to already existing ones. /// public Project AddProjectReferences(IEnumerable projectReferences) - => this.Solution.AddProjectReferences(this.Id, projectReferences).GetProject(this.Id)!; + => this.Solution.AddProjectReferences(this.Id, projectReferences).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to no longer include the specified project reference. /// public Project RemoveProjectReference(ProjectReference projectReference) - => this.Solution.RemoveProjectReference(this.Id, projectReference).GetProject(this.Id)!; + => this.Solution.RemoveProjectReference(this.Id, projectReference).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to replace existing project references /// with the specified ones. /// public Project WithProjectReferences(IEnumerable projectReferences) - => this.Solution.WithProjectReferences(this.Id, projectReferences).GetProject(this.Id)!; + => this.Solution.WithProjectReferences(this.Id, projectReferences).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to include the specified metadata reference /// in addition to already existing ones. /// public Project AddMetadataReference(MetadataReference metadataReference) - => this.Solution.AddMetadataReference(this.Id, metadataReference).GetProject(this.Id)!; + => this.Solution.AddMetadataReference(this.Id, metadataReference).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to include the specified metadata references /// in addition to already existing ones. /// public Project AddMetadataReferences(IEnumerable metadataReferences) - => this.Solution.AddMetadataReferences(this.Id, metadataReferences).GetProject(this.Id)!; + => this.Solution.AddMetadataReferences(this.Id, metadataReferences).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to no longer include the specified metadata reference. /// public Project RemoveMetadataReference(MetadataReference metadataReference) - => this.Solution.RemoveMetadataReference(this.Id, metadataReference).GetProject(this.Id)!; + => this.Solution.RemoveMetadataReference(this.Id, metadataReference).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to replace existing metadata reference /// with the specified ones. /// public Project WithMetadataReferences(IEnumerable metadataReferences) - => this.Solution.WithProjectMetadataReferences(this.Id, metadataReferences).GetProject(this.Id)!; + => this.Solution.WithProjectMetadataReferences(this.Id, metadataReferences).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to include the specified analyzer reference /// in addition to already existing ones. /// public Project AddAnalyzerReference(AnalyzerReference analyzerReference) - => this.Solution.AddAnalyzerReference(this.Id, analyzerReference).GetProject(this.Id)!; + => this.Solution.AddAnalyzerReference(this.Id, analyzerReference).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to include the specified analyzer references /// in addition to already existing ones. /// public Project AddAnalyzerReferences(IEnumerable analyzerReferences) - => this.Solution.AddAnalyzerReferences(this.Id, analyzerReferences).GetProject(this.Id)!; + => this.Solution.AddAnalyzerReferences(this.Id, analyzerReferences).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to no longer include the specified analyzer reference. /// public Project RemoveAnalyzerReference(AnalyzerReference analyzerReference) - => this.Solution.RemoveAnalyzerReference(this.Id, analyzerReference).GetProject(this.Id)!; + => this.Solution.RemoveAnalyzerReference(this.Id, analyzerReference).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to replace existing analyzer references /// with the specified ones. /// public Project WithAnalyzerReferences(IEnumerable analyzerReferencs) - => this.Solution.WithProjectAnalyzerReferences(this.Id, analyzerReferencs).GetProject(this.Id)!; + => this.Solution.WithProjectAnalyzerReferences(this.Id, analyzerReferencs).GetRequiredProject(Id); + + /// + /// Creates a new instance of this project updated to replace existing analyzer references + /// with the specified ones. + /// + internal Project WithAttributes(ProjectInfo.ProjectAttributes attributes) + => Solution.WithProjectAttributes(attributes).GetRequiredProject(Id); /// /// Creates a new document in a new instance of this project. @@ -739,7 +744,7 @@ public Project RemoveDocument(DocumentId documentId) { // NOTE: the method isn't checking if documentId belongs to the project. This probably should be done, but may be a compat change. // https://github.com/dotnet/roslyn/issues/41211 tracks this investigation. - return this.Solution.RemoveDocument(documentId).GetProject(this.Id)!; + return this.Solution.RemoveDocument(documentId).GetRequiredProject(Id); } /// @@ -758,7 +763,7 @@ public Project RemoveDocuments(ImmutableArray documentIds) public Project RemoveAdditionalDocument(DocumentId documentId) // NOTE: the method isn't checking if documentId belongs to the project. This probably should be done, but may be a compat change. // https://github.com/dotnet/roslyn/issues/41211 tracks this investigation. - => this.Solution.RemoveAdditionalDocument(documentId).GetProject(this.Id)!; + => this.Solution.RemoveAdditionalDocument(documentId).GetRequiredProject(Id); /// /// Creates a new instance of this project updated to no longer include the specified additional documents. @@ -776,7 +781,7 @@ public Project RemoveAdditionalDocuments(ImmutableArray documentIds) public Project RemoveAnalyzerConfigDocument(DocumentId documentId) // NOTE: the method isn't checking if documentId belongs to the project. This probably should be done, but may be a compat change. // https://github.com/dotnet/roslyn/issues/41211 tracks this investigation. - => this.Solution.RemoveAnalyzerConfigDocument(documentId).GetProject(this.Id)!; + => this.Solution.RemoveAnalyzerConfigDocument(documentId).GetRequiredProject(Id); /// /// Creates a new solution instance that no longer includes the specified s. @@ -801,13 +806,13 @@ private void CheckIdsContainedInProject(ImmutableArray documentIds) } internal AnalyzerConfigData? GetAnalyzerConfigOptions() - => _projectState.GetAnalyzerConfigOptions(); + => State.GetAnalyzerConfigOptions(); /// /// Retrieves fallback analyzer options for this project's language. /// internal StructuredAnalyzerConfigOptions GetFallbackAnalyzerOptions() - => _solution.FallbackAnalyzerOptions.GetValueOrDefault(Language, StructuredAnalyzerConfigOptions.Empty); + => Solution.FallbackAnalyzerOptions.GetValueOrDefault(Language, StructuredAnalyzerConfigOptions.Empty); private string GetDebuggerDisplay() => this.Name; @@ -817,7 +822,7 @@ internal SkippedHostAnalyzersInfo GetSkippedAnalyzersInfo(DiagnosticAnalyzerInfo internal async ValueTask GetDocumentAsync(ImmutableArray contentHash, CancellationToken cancellationToken) { - var documentId = await _projectState.GetDocumentIdAsync(contentHash, cancellationToken).ConfigureAwait(false); + var documentId = await State.GetDocumentIdAsync(contentHash, cancellationToken).ConfigureAwait(false); return documentId is null ? null : GetDocument(documentId); } } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectChanges.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectChanges.cs index b86ede6edd7ec..c302ead8094f1 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectChanges.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectChanges.cs @@ -9,25 +9,22 @@ namespace Microsoft.CodeAnalysis; public readonly struct ProjectChanges { - private readonly Project _newProject; - private readonly Project _oldProject; - internal ProjectChanges(Project newProject, Project oldProject) { - _newProject = newProject; - _oldProject = oldProject; + NewProject = newProject; + OldProject = oldProject; } - public ProjectId ProjectId => _newProject.Id; + public ProjectId ProjectId => NewProject.Id; - public Project OldProject => _oldProject; + public Project OldProject { get; } - public Project NewProject => _newProject; + public Project NewProject { get; } public IEnumerable GetAddedProjectReferences() { - var oldRefs = new HashSet(_oldProject.ProjectReferences); - foreach (var reference in _newProject.ProjectReferences) + var oldRefs = new HashSet(OldProject.ProjectReferences); + foreach (var reference in NewProject.ProjectReferences) { if (!oldRefs.Contains(reference)) { @@ -38,8 +35,8 @@ public IEnumerable GetAddedProjectReferences() public IEnumerable GetRemovedProjectReferences() { - var newRefs = new HashSet(_newProject.ProjectReferences); - foreach (var reference in _oldProject.ProjectReferences) + var newRefs = new HashSet(NewProject.ProjectReferences); + foreach (var reference in OldProject.ProjectReferences) { if (!newRefs.Contains(reference)) { @@ -50,8 +47,8 @@ public IEnumerable GetRemovedProjectReferences() public IEnumerable GetAddedMetadataReferences() { - var oldMetadata = new HashSet(_oldProject.MetadataReferences); - foreach (var metadata in _newProject.MetadataReferences) + var oldMetadata = new HashSet(OldProject.MetadataReferences); + foreach (var metadata in NewProject.MetadataReferences) { if (!oldMetadata.Contains(metadata)) { @@ -62,8 +59,8 @@ public IEnumerable GetAddedMetadataReferences() public IEnumerable GetRemovedMetadataReferences() { - var newMetadata = new HashSet(_newProject.MetadataReferences); - foreach (var metadata in _oldProject.MetadataReferences) + var newMetadata = new HashSet(NewProject.MetadataReferences); + foreach (var metadata in OldProject.MetadataReferences) { if (!newMetadata.Contains(metadata)) { @@ -74,8 +71,8 @@ public IEnumerable GetRemovedMetadataReferences() public IEnumerable GetAddedAnalyzerReferences() { - var oldAnalyzerReferences = new HashSet(_oldProject.AnalyzerReferences); - foreach (var analyzerReference in _newProject.AnalyzerReferences) + var oldAnalyzerReferences = new HashSet(OldProject.AnalyzerReferences); + foreach (var analyzerReference in NewProject.AnalyzerReferences) { if (!oldAnalyzerReferences.Contains(analyzerReference)) { @@ -86,8 +83,8 @@ public IEnumerable GetAddedAnalyzerReferences() public IEnumerable GetRemovedAnalyzerReferences() { - var newAnalyzerReferences = new HashSet(_newProject.AnalyzerReferences); - foreach (var analyzerReference in _oldProject.AnalyzerReferences) + var newAnalyzerReferences = new HashSet(NewProject.AnalyzerReferences); + foreach (var analyzerReference in OldProject.AnalyzerReferences) { if (!newAnalyzerReferences.Contains(analyzerReference)) { @@ -100,19 +97,19 @@ public IEnumerable GetRemovedAnalyzerReferences() /// Get s of added documents in the order they appear in of the . /// public IEnumerable GetAddedDocuments() - => _newProject.State.DocumentStates.GetAddedStateIds(_oldProject.State.DocumentStates); + => NewProject.State.DocumentStates.GetAddedStateIds(OldProject.State.DocumentStates); /// /// Get s of added dditional documents in the order they appear in of . /// public IEnumerable GetAddedAdditionalDocuments() - => _newProject.State.AdditionalDocumentStates.GetAddedStateIds(_oldProject.State.AdditionalDocumentStates); + => NewProject.State.AdditionalDocumentStates.GetAddedStateIds(OldProject.State.AdditionalDocumentStates); /// /// Get s of added analyzer config documents in the order they appear in of . /// public IEnumerable GetAddedAnalyzerConfigDocuments() - => _newProject.State.AnalyzerConfigDocumentStates.GetAddedStateIds(_oldProject.State.AnalyzerConfigDocumentStates); + => NewProject.State.AnalyzerConfigDocumentStates.GetAddedStateIds(OldProject.State.AnalyzerConfigDocumentStates); /// /// Get s of documents with any changes (textual and non-textual) @@ -130,37 +127,37 @@ public IEnumerable GetChangedDocuments(bool onlyGetDocumentsWithText => GetChangedDocuments(onlyGetDocumentsWithTextChanges, ignoreUnchangeableDocuments: false); internal IEnumerable GetChangedDocuments(bool onlyGetDocumentsWithTextChanges, bool ignoreUnchangeableDocuments) - => _newProject.State.DocumentStates.GetChangedStateIds(_oldProject.State.DocumentStates, onlyGetDocumentsWithTextChanges, ignoreUnchangeableDocuments); + => NewProject.State.DocumentStates.GetChangedStateIds(OldProject.State.DocumentStates, onlyGetDocumentsWithTextChanges, ignoreUnchangeableDocuments); /// /// Get s of additional documents with any changes (textual and non-textual) /// in the order they appear in of . /// public IEnumerable GetChangedAdditionalDocuments() - => _newProject.State.AdditionalDocumentStates.GetChangedStateIds(_oldProject.State.AdditionalDocumentStates); + => NewProject.State.AdditionalDocumentStates.GetChangedStateIds(OldProject.State.AdditionalDocumentStates); /// /// Get s of analyzer config documents with any changes (textual and non-textual) /// in the order they appear in of . /// public IEnumerable GetChangedAnalyzerConfigDocuments() - => _newProject.State.AnalyzerConfigDocumentStates.GetChangedStateIds(_oldProject.State.AnalyzerConfigDocumentStates); + => NewProject.State.AnalyzerConfigDocumentStates.GetChangedStateIds(OldProject.State.AnalyzerConfigDocumentStates); /// /// Get s of removed documents in the order they appear in of . /// public IEnumerable GetRemovedDocuments() - => _newProject.State.DocumentStates.GetRemovedStateIds(_oldProject.State.DocumentStates); + => NewProject.State.DocumentStates.GetRemovedStateIds(OldProject.State.DocumentStates); /// /// Get s of removed additional documents in the order they appear in of . /// public IEnumerable GetRemovedAdditionalDocuments() - => _newProject.State.AdditionalDocumentStates.GetRemovedStateIds(_oldProject.State.AdditionalDocumentStates); + => NewProject.State.AdditionalDocumentStates.GetRemovedStateIds(OldProject.State.AdditionalDocumentStates); /// /// Get s of removed analyzer config documents in the order they appear in of . /// public IEnumerable GetRemovedAnalyzerConfigDocuments() - => _newProject.State.AnalyzerConfigDocumentStates.GetRemovedStateIds(_oldProject.State.AnalyzerConfigDocumentStates); + => NewProject.State.AnalyzerConfigDocumentStates.GetRemovedStateIds(OldProject.State.AnalyzerConfigDocumentStates); } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs index 5d1b58e2b371f..d972b541b4d0b 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs @@ -17,7 +17,6 @@ namespace Microsoft.CodeAnalysis; /// public partial class ProjectDependencyGraph { - private readonly ImmutableHashSet _projectIds; /// /// The map of projects to dependencies. This field is always fully initialized. Projects which do not reference @@ -29,7 +28,7 @@ public partial class ProjectDependencyGraph /// Projects which do not reference any other projects do not have a key in this map (i.e. /// they are omitted, as opposed to including them with an empty value) /// The keys and values in this map are always contained in - /// + /// /// /// private readonly ImmutableDictionary> _referencesMap; @@ -97,7 +96,7 @@ private ProjectDependencyGraph( Contract.ThrowIfNull(transitiveReferencesMap); Contract.ThrowIfNull(reverseTransitiveReferencesMap); - _projectIds = projectIds; + ProjectIds = projectIds; _referencesMap = referencesMap; _lazyReverseReferencesMap = reverseReferencesMap; _transitiveReferencesMap = transitiveReferencesMap; @@ -105,11 +104,11 @@ private ProjectDependencyGraph( _lazyTopologicallySortedProjects = topologicallySortedProjects; _lazyDependencySets = dependencySets; - ValidateForwardReferences(_projectIds, _referencesMap); - ValidateReverseReferences(_projectIds, _referencesMap, _lazyReverseReferencesMap); + ValidateForwardReferences(ProjectIds, _referencesMap); + ValidateReverseReferences(ProjectIds, _referencesMap, _lazyReverseReferencesMap); } - internal ImmutableHashSet ProjectIds => _projectIds; + internal ImmutableHashSet ProjectIds { get; } private static ImmutableDictionary> RemoveItemsWithEmptyValues( ImmutableDictionary> map) @@ -131,7 +130,7 @@ private static ImmutableDictionary> Remov internal ProjectDependencyGraph WithProjectReferences(ProjectId projectId, IReadOnlyList projectReferences) { - Contract.ThrowIfFalse(_projectIds.Contains(projectId)); + Contract.ThrowIfFalse(ProjectIds.Contains(projectId)); if (!_referencesMap.ContainsKey(projectId)) { @@ -150,14 +149,14 @@ internal ProjectDependencyGraph WithProjectReferences(ProjectId projectId, IRead // only include projects contained in the solution: var referencedProjectIds = projectReferences.IsEmpty() ? [] : projectReferences - .Where(r => _projectIds.Contains(r.ProjectId)) + .Where(r => ProjectIds.Contains(r.ProjectId)) .Select(r => r.ProjectId) .ToImmutableHashSet(); var referencesMap = referencedProjectIds.IsEmpty ? _referencesMap.Remove(projectId) : _referencesMap.SetItem(projectId, referencedProjectIds); - return new ProjectDependencyGraph(_projectIds, referencesMap); + return new ProjectDependencyGraph(ProjectIds, referencesMap); } /// @@ -202,7 +201,7 @@ private ImmutableHashSet GetProjectsThatDirectlyDependOnThisProject_N if (_lazyReverseReferencesMap == null) { _lazyReverseReferencesMap = this.ComputeReverseReferencesMap(); - ValidateReverseReferences(_projectIds, _referencesMap, _lazyReverseReferencesMap); + ValidateReverseReferences(ProjectIds, _referencesMap, _lazyReverseReferencesMap); } return _lazyReverseReferencesMap.GetValueOrDefault(projectId, []); @@ -366,7 +365,7 @@ private void GetTopologicallySortedProjects_NoLock(CancellationToken cancellatio { using var seenProjects = SharedPools.Default>().GetPooledObject(); using var resultList = SharedPools.Default>().GetPooledObject(); - this.TopologicalSort(_projectIds, seenProjects.Object, resultList.Object, cancellationToken); + this.TopologicalSort(ProjectIds, seenProjects.Object, resultList.Object, cancellationToken); _lazyTopologicallySortedProjects = [.. resultList.Object]; } } @@ -427,7 +426,7 @@ private ImmutableArray> GetDependencySets_NoLock(Cancella private void ComputeDependencySets(HashSet seenProjects, List> results, CancellationToken cancellationToken) { - foreach (var project in _projectIds) + foreach (var project in ProjectIds) { if (seenProjects.Add(project)) { diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProject.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProject.cs index 8f98943e1afce..4fd25be9af3ab 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProject.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProject.cs @@ -34,7 +34,7 @@ internal ProjectDependencyGraph WithAdditionalProject(ProjectId projectId) // The rest of the references map is unchanged, since no new references are added in this call. return new ProjectDependencyGraph( - _projectIds.Add(projectId), + ProjectIds.Add(projectId), referencesMap: _referencesMap, reverseReferencesMap: _lazyReverseReferencesMap, transitiveReferencesMap: _transitiveReferencesMap, diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProjectReference.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProjectReference.cs index d7e48d3bf3dd3..96ce0d9a57e76 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProjectReference.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_AddProjectReference.cs @@ -14,7 +14,7 @@ public partial class ProjectDependencyGraph { internal ProjectDependencyGraph WithAdditionalProjectReferences(ProjectId projectId, IReadOnlyCollection projectReferences) { - Contract.ThrowIfFalse(_projectIds.Contains(projectId)); + Contract.ThrowIfFalse(ProjectIds.Contains(projectId)); if (projectReferences.Count == 0) { @@ -23,7 +23,7 @@ internal ProjectDependencyGraph WithAdditionalProjectReferences(ProjectId projec // only add references to projects that are contained in the solution/graph var referencedProjectIds = projectReferences - .Where(r => _projectIds.Contains(r.ProjectId)) + .Where(r => ProjectIds.Contains(r.ProjectId)) .Select(r => r.ProjectId) .ToList(); @@ -43,7 +43,7 @@ internal ProjectDependencyGraph WithAdditionalProjectReferences(ProjectId projec // Note: rather than updating our dependency sets and topologically sorted data, we'll throw that away since incremental update is // tricky, and those are rarely used. If somebody needs them, it'll be lazily computed. return new ProjectDependencyGraph( - _projectIds, + ProjectIds, referencesMap: newReferencesMap, reverseReferencesMap: newReverseReferencesMap, transitiveReferencesMap: newTransitiveReferencesMap, diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveAllProjectReferences.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveAllProjectReferences.cs index df79d671d54bb..671f47c514c23 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveAllProjectReferences.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveAllProjectReferences.cs @@ -12,13 +12,13 @@ public partial class ProjectDependencyGraph { internal ProjectDependencyGraph WithAllProjectReferencesRemoved(ProjectId projectId) { - Contract.ThrowIfFalse(_projectIds.Contains(projectId)); + Contract.ThrowIfFalse(ProjectIds.Contains(projectId)); if (!_referencesMap.TryGetValue(projectId, out var referencedProjectIds)) return this; // Removing a project reference doesn't change the set of projects - var projectIds = _projectIds; + var projectIds = ProjectIds; // Incrementally update the graph var referencesMap = ComputeNewReferencesMapForRemovedAllProjectReferences(_referencesMap, projectId); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveProject.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveProject.cs index 05475dc7af517..de4d45db83feb 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveProject.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveProject.cs @@ -11,11 +11,11 @@ public partial class ProjectDependencyGraph { internal ProjectDependencyGraph WithProjectRemoved(ProjectId projectId) { - Contract.ThrowIfFalse(_projectIds.Contains(projectId)); + Contract.ThrowIfFalse(ProjectIds.Contains(projectId)); // Project ID set and direct forward references are trivially updated by removing the key corresponding to // the project getting removed. - var projectIds = _projectIds.Remove(projectId); + var projectIds = ProjectIds.Remove(projectId); var referencesMap = ComputeNewReferencesMapForRemovedProject( existingForwardReferencesMap: _referencesMap, existingReverseReferencesMap: _lazyReverseReferencesMap, diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveProjectReference.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveProjectReference.cs index be6adbe37ebcc..d0c569c34c9fa 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveProjectReference.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveProjectReference.cs @@ -12,11 +12,11 @@ public partial class ProjectDependencyGraph { internal ProjectDependencyGraph WithProjectReferenceRemoved(ProjectId projectId, ProjectId referencedProjectId) { - Contract.ThrowIfFalse(_projectIds.Contains(projectId)); + Contract.ThrowIfFalse(ProjectIds.Contains(projectId)); Contract.ThrowIfFalse(_referencesMap[projectId].Contains(referencedProjectId)); // Removing a project reference doesn't change the set of projects - var projectIds = _projectIds; + var projectIds = ProjectIds; // Incrementally update the graph var referencesMap = ComputeNewReferencesMapForRemovedProjectReference(_referencesMap, projectId, referencedProjectId); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectInfo.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectInfo.cs index 75589b6dd8c3d..391486737ce7f 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectInfo.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectInfo.cs @@ -326,6 +326,9 @@ internal ProjectInfo With( newHostObjectType); } + public ProjectInfo WithId(ProjectId id) + => With(attributes: Attributes.With(id: id ?? throw new ArgumentNullException(nameof(id)))); + public ProjectInfo WithVersion(VersionStamp version) => With(attributes: Attributes.With(version: version)); @@ -511,6 +514,7 @@ internal sealed class ProjectAttributes( }, this); public ProjectAttributes With( + ProjectId? id = null, VersionStamp? version = null, string? name = null, string? assemblyName = null, @@ -525,6 +529,7 @@ public ProjectAttributes With( Optional runAnalyzers = default, Optional telemetryId = default) { + var newId = id ?? Id; var newVersion = version ?? Version; var newName = name ?? Name; var newAssemblyName = assemblyName ?? AssemblyName; @@ -539,7 +544,8 @@ public ProjectAttributes With( var newRunAnalyzers = runAnalyzers.HasValue ? runAnalyzers.Value : RunAnalyzers; var newTelemetryId = telemetryId.HasValue ? telemetryId.Value : TelemetryId; - if (newVersion == Version && + if (newId == Id && + newVersion == Version && newName == Name && newAssemblyName == AssemblyName && newFilePath == FilePath && @@ -557,7 +563,7 @@ public ProjectAttributes With( } return new ProjectAttributes( - Id, + newId, newVersion, newName, newAssemblyName, diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectReference.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectReference.cs index 2806e8d348f31..bcf06af9e691b 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectReference.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectReference.cs @@ -16,30 +16,26 @@ namespace Microsoft.CodeAnalysis; [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] public sealed class ProjectReference : IEquatable { - private readonly ProjectId _projectId; - private readonly ImmutableArray _aliases; - private readonly bool _embedInteropTypes; - public ProjectReference(ProjectId projectId, ImmutableArray aliases = default, bool embedInteropTypes = false) { Contract.ThrowIfNull(projectId); - _projectId = projectId; - _aliases = aliases.NullToEmpty(); - _embedInteropTypes = embedInteropTypes; + ProjectId = projectId; + Aliases = aliases.NullToEmpty(); + EmbedInteropTypes = embedInteropTypes; } - public ProjectId ProjectId => _projectId; + public ProjectId ProjectId { get; } /// /// Aliases for the reference. Empty if the reference has no aliases. /// - public ImmutableArray Aliases => _aliases; + public ImmutableArray Aliases { get; } /// /// True if interop types defined in the referenced project should be embedded into the referencing project. /// - public bool EmbedInteropTypes => _embedInteropTypes; + public bool EmbedInteropTypes { get; } public override bool Equals(object obj) => this.Equals(obj as ProjectReference); @@ -52,9 +48,9 @@ public bool Equals(ProjectReference reference) } return reference is object && - _projectId == reference._projectId && - _aliases.SequenceEqual(reference._aliases) && - _embedInteropTypes == reference._embedInteropTypes; + ProjectId == reference.ProjectId && + Aliases.SequenceEqual(reference.Aliases) && + EmbedInteropTypes == reference.EmbedInteropTypes; } public static bool operator ==(ProjectReference left, ProjectReference right) @@ -64,8 +60,8 @@ public bool Equals(ProjectReference reference) => !(left == right); public override int GetHashCode() - => Hash.CombineValues(_aliases, Hash.Combine(_projectId, _embedInteropTypes.GetHashCode())); + => Hash.CombineValues(Aliases, Hash.Combine(ProjectId, EmbedInteropTypes.GetHashCode())); private string GetDebuggerDisplay() - => _projectId.ToString(); + => ProjectId.ToString(); } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs index 7dec7399150f1..b6cf790c348d9 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs @@ -25,7 +25,6 @@ namespace Microsoft.CodeAnalysis; internal partial class ProjectState { - private readonly ProjectInfo _projectInfo; public readonly LanguageServices LanguageServices; /// @@ -82,7 +81,7 @@ private ProjectState( // ownership of information on document has moved to project state. clear out documentInfo the state is // holding on. otherwise, these information will be held onto unnecessarily by projectInfo even after // the info has changed by DocumentState. - _projectInfo = ClearAllDocumentsFromProjectInfo(projectInfo); + ProjectInfo = ClearAllDocumentsFromProjectInfo(projectInfo); _lazyChecksums = AsyncLazy.Create(static (self, cancellationToken) => self.ComputeChecksumsAsync(cancellationToken), arg: this); _lazyContentHashToDocumentId = AsyncLazy.Create(static (self, cancellationToken) => self.ComputeContentHashToDocumentIdAsync(cancellationToken), arg: this); @@ -123,12 +122,20 @@ public ProjectState(LanguageServices languageServices, ProjectInfo projectInfo, // holding on. otherwise, these information will be held onto unnecessarily by projectInfo even after // the info has changed by DocumentState. // we hold onto the info so that we don't need to duplicate all information info already has in the state - _projectInfo = ClearAllDocumentsFromProjectInfo(projectInfoFixed); + ProjectInfo = ClearAllDocumentsFromProjectInfo(projectInfoFixed); _lazyChecksums = AsyncLazy.Create(static (self, cancellationToken) => self.ComputeChecksumsAsync(cancellationToken), arg: this); _lazyContentHashToDocumentId = AsyncLazy.Create(static (self, cancellationToken) => self.ComputeContentHashToDocumentIdAsync(cancellationToken), arg: this); } + public TextDocumentStates GetDocumentStates() + where TDocumentState : TextDocumentState + => (TextDocumentStates)(object)( + typeof(TDocumentState) == typeof(DocumentState) ? DocumentStates : + typeof(TDocumentState) == typeof(AdditionalDocumentState) ? AdditionalDocumentStates : + typeof(TDocumentState) == typeof(AnalyzerConfigDocumentState) ? AnalyzerConfigDocumentStates : + throw ExceptionUtilities.UnexpectedValue(typeof(TDocumentState))); + private async Task, DocumentId>> ComputeContentHashToDocumentIdAsync(CancellationToken cancellationToken) { var result = new Dictionary, DocumentId>(ImmutableArrayComparer.Instance); @@ -266,7 +273,7 @@ private static async Task ComputeLatestDocumentTopLevelChangeVersi internal DocumentState CreateDocument(DocumentInfo documentInfo, ParseOptions? parseOptions, LoadTextOptions loadTextOptions) { - var doc = new DocumentState(LanguageServices, documentInfo, parseOptions, loadTextOptions); + var doc = DocumentState.Create(LanguageServices, documentInfo, parseOptions, loadTextOptions); if (doc.SourceCodeKind != documentInfo.SourceCodeKind) { @@ -276,6 +283,14 @@ internal DocumentState CreateDocument(DocumentInfo documentInfo, ParseOptions? p return doc; } + internal TDocumentState CreateDocument(DocumentInfo documentInfo) + where TDocumentState : TextDocumentState + => (TDocumentState)(object)( + typeof(TDocumentState) == typeof(DocumentState) ? CreateDocument(documentInfo, ParseOptions, new LoadTextOptions(ChecksumAlgorithm)) : + typeof(TDocumentState) == typeof(AdditionalDocumentState) ? new AdditionalDocumentState(LanguageServices.SolutionServices, documentInfo, new LoadTextOptions(ChecksumAlgorithm)) : + typeof(TDocumentState) == typeof(AnalyzerConfigDocumentState) ? new AnalyzerConfigDocumentState(LanguageServices.SolutionServices, documentInfo, new LoadTextOptions(ChecksumAlgorithm)) : + throw ExceptionUtilities.UnexpectedValue(typeof(TDocumentState))); + public AnalyzerOptions AnalyzerOptions => _lazyAnalyzerOptions ??= new AnalyzerOptions( additionalFiles: AdditionalDocumentStates.SelectAsArray(static documentState => documentState.AdditionalText), @@ -286,7 +301,7 @@ public AnalyzerConfigData GetAnalyzerOptionsForPath(string path, CancellationTok public AnalyzerConfigData? GetAnalyzerConfigOptions() { - var extension = _projectInfo.Language switch + var extension = ProjectInfo.Language switch { LanguageNames.CSharp => ".cs", LanguageNames.VisualBasic => ".vb", @@ -298,7 +313,7 @@ public AnalyzerConfigData GetAnalyzerOptionsForPath(string path, CancellationTok return null; } - if (!PathUtilities.IsAbsolute(_projectInfo.FilePath)) + if (!PathUtilities.IsAbsolute(ProjectInfo.FilePath)) { return null; } @@ -309,7 +324,7 @@ public AnalyzerConfigData GetAnalyzerOptionsForPath(string path, CancellationTok // NIL character is invalid in paths so it will never match any pattern in editorconfig, but editorconfig parsing allows it. // TODO: https://github.com/dotnet/roslyn/issues/61217 - var projectDirectory = PathUtilities.GetDirectoryName(_projectInfo.FilePath); + var projectDirectory = PathUtilities.GetDirectoryName(ProjectInfo.FilePath); Contract.ThrowIfNull(projectDirectory); var sourceFilePath = PathUtilities.CombinePathsUnchecked(projectDirectory, "\0" + extension); @@ -537,7 +552,7 @@ public async Task GetSemanticVersionAsync(CancellationToken cancel public VersionStamp Version => this.ProjectInfo.Version; [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] - public ProjectInfo ProjectInfo => _projectInfo; + public ProjectInfo ProjectInfo { get; } [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] public string AssemblyName => this.ProjectInfo.AssemblyName; @@ -573,7 +588,7 @@ private ProjectState With( AnalyzerConfigOptionsCache? analyzerConfigOptionsCache = null) { return new ProjectState( - projectInfo ?? _projectInfo, + projectInfo ?? ProjectInfo, LanguageServices, documentStates ?? DocumentStates, additionalDocumentStates ?? AdditionalDocumentStates, @@ -639,32 +654,44 @@ public ProjectState WithChecksumAlgorithm(SourceHashAlgorithm checksumAlgorithm) private TextDocumentStates UpdateDocumentsChecksumAlgorithm(SourceHashAlgorithm checksumAlgorithm) => DocumentStates.UpdateStates(static (state, checksumAlgorithm) => state.UpdateChecksumAlgorithm(checksumAlgorithm), checksumAlgorithm); - public ProjectState WithCompilationOptions(CompilationOptions options) + public ProjectState WithCompilationOptions(CompilationOptions? options) { if (options == CompilationOptions) { return this; } + if (options == null) + { + throw new NotSupportedException(WorkspacesResources.Removing_compilation_options_is_not_supported); + } + var newProvider = new ProjectSyntaxTreeOptionsProvider(_analyzerConfigOptionsCache); return With(projectInfo: ProjectInfo.WithCompilationOptions(options.WithSyntaxTreeOptionsProvider(newProvider)) .WithVersion(Version.GetNewerVersion())); } - public ProjectState WithParseOptions(ParseOptions options) + public ProjectState WithParseOptions(ParseOptions? options) { if (options == ParseOptions) { return this; } + if (options == null) + { + throw new NotSupportedException(WorkspacesResources.Removing_parse_options_is_not_supported); + } + var onlyPreprocessorDirectiveChange = ParseOptions != null && LanguageServices.GetRequiredService().OptionsDifferOnlyByPreprocessorDirectives(options, ParseOptions); return With( projectInfo: ProjectInfo.WithParseOptions(options).WithVersion(Version.GetNewerVersion()), - documentStates: DocumentStates.UpdateStates(static (state, args) => state.UpdateParseOptions(args.options, args.onlyPreprocessorDirectiveChange), (options, onlyPreprocessorDirectiveChange))); + documentStates: DocumentStates.UpdateStates(static (state, args) => + state.UpdateParseOptionsAndSourceCodeKind(args.options, args.onlyPreprocessorDirectiveChange), + arg: (options, onlyPreprocessorDirectiveChange))); } public ProjectState WithFallbackAnalyzerOptions(StructuredAnalyzerConfigOptions options) @@ -827,27 +854,25 @@ public ProjectState RemoveAllNormalDocuments() analyzerConfigOptionsCache: new AnalyzerConfigOptionsCache(AnalyzerConfigDocumentStates, _analyzerConfigOptionsCache.FallbackOptions)); } - public ProjectState UpdateDocument(DocumentState newDocument, bool contentChanged) - => UpdateDocuments([newDocument], contentChanged); + public ProjectState UpdateDocument(DocumentState newDocument) + => UpdateDocuments([DocumentStates.GetRequiredState(newDocument.Id)], [newDocument]); - public ProjectState UpdateDocuments(ImmutableArray newDocuments, bool contentChanged) + public ProjectState UpdateDocuments(ImmutableArray oldDocuments, ImmutableArray newDocuments) { - var oldDocuments = newDocuments.SelectAsArray(d => DocumentStates.GetRequiredState(d.Id)); - if (oldDocuments.SequenceEqual(newDocuments)) - return this; - - // Must not be empty as we would have otherwise bailed out in the check above. - Contract.ThrowIfTrue(newDocuments.IsEmpty); + Contract.ThrowIfTrue(oldDocuments.IsEmpty); + Contract.ThrowIfFalse(oldDocuments.Length == newDocuments.Length); + Debug.Assert(!oldDocuments.SequenceEqual(newDocuments)); var newDocumentStates = DocumentStates.SetStates(newDocuments); // When computing the latest dependent version, we just need to know how GetLatestDependentVersions( - newDocumentStates, AdditionalDocumentStates, + newDocumentStates, + AdditionalDocumentStates, oldDocuments.CastArray(), newDocuments.CastArray(), - contentChanged, - out var dependentDocumentVersion, out var dependentSemanticVersion); + out var dependentDocumentVersion, + out var dependentSemanticVersion); return With( documentStates: newDocumentStates, @@ -855,35 +880,38 @@ public ProjectState UpdateDocuments(ImmutableArray newDocuments, latestDocumentTopLevelChangeVersion: dependentSemanticVersion); } - public ProjectState UpdateAdditionalDocument(AdditionalDocumentState newDocument, bool contentChanged) + public ProjectState UpdateAdditionalDocument(AdditionalDocumentState newDocument) + => UpdateAdditionalDocuments([AdditionalDocumentStates.GetRequiredState(newDocument.Id)], [newDocument]); + + public ProjectState UpdateAdditionalDocuments(ImmutableArray oldDocuments, ImmutableArray newDocuments) { - var oldDocument = AdditionalDocumentStates.GetRequiredState(newDocument.Id); - if (oldDocument == newDocument) - { - return this; - } + Contract.ThrowIfTrue(oldDocuments.IsEmpty); + Contract.ThrowIfFalse(oldDocuments.Length == newDocuments.Length); + Debug.Assert(!oldDocuments.SequenceEqual(newDocuments)); + + var newDocumentStates = AdditionalDocumentStates.SetStates(newDocuments); - var newDocumentStates = AdditionalDocumentStates.SetState(newDocument); GetLatestDependentVersions( - DocumentStates, newDocumentStates, [oldDocument], [newDocument], contentChanged, - out var dependentDocumentVersion, out var dependentSemanticVersion); + DocumentStates, + newDocumentStates, + oldDocuments.CastArray(), + newDocuments.CastArray(), + out var dependentDocumentVersion, + out var dependentSemanticVersion); - return this.With( + return With( additionalDocumentStates: newDocumentStates, latestDocumentVersion: dependentDocumentVersion, latestDocumentTopLevelChangeVersion: dependentSemanticVersion); } public ProjectState UpdateAnalyzerConfigDocument(AnalyzerConfigDocumentState newDocument) - { - var oldDocument = AnalyzerConfigDocumentStates.GetRequiredState(newDocument.Id); - if (oldDocument == newDocument) - { - return this; - } - - var newDocumentStates = AnalyzerConfigDocumentStates.SetState(newDocument); + => UpdateAnalyzerConfigDocuments([AnalyzerConfigDocumentStates.GetRequiredState(newDocument.Id)], [newDocument]); + public ProjectState UpdateAnalyzerConfigDocuments(ImmutableArray oldDocuments, ImmutableArray newDocuments) + { + Debug.Assert(!oldDocuments.SequenceEqual(newDocuments)); + var newDocumentStates = AnalyzerConfigDocumentStates.SetStates(newDocuments); return CreateNewStateForChangedAnalyzerConfig(newDocumentStates, _analyzerConfigOptionsCache.FallbackOptions); } @@ -904,13 +932,16 @@ private void GetLatestDependentVersions( TextDocumentStates newAdditionalDocumentStates, ImmutableArray oldDocuments, ImmutableArray newDocuments, - bool contentChanged, out AsyncLazy dependentDocumentVersion, out AsyncLazy dependentSemanticVersion) { var recalculateDocumentVersion = false; var recalculateSemanticVersion = false; + var contentChanged = !oldDocuments.SequenceEqual( + newDocuments, + static (oldDocument, newDocument) => oldDocument.TextAndVersionSource == newDocument.TextAndVersionSource); + if (contentChanged) { foreach (var oldDocument in oldDocuments) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs index 438640169d706..796fa8e99cf79 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; @@ -26,7 +27,6 @@ namespace Microsoft.CodeAnalysis; /// public partial class Solution { - private readonly SolutionCompilationState _compilationState; // Values for all these are created on demand. private ImmutableDictionary _projectIdToProjectMap; @@ -47,7 +47,7 @@ private Solution( AsyncLazy? cachedFrozenSolution = null) { _projectIdToProjectMap = ImmutableDictionary.Empty; - _compilationState = compilationState; + CompilationState = compilationState; _cachedFrozenSolution = cachedFrozenSolution ?? AsyncLazy.Create(synchronousComputeFunction: static (self, c) => @@ -69,11 +69,11 @@ internal Solution( internal SolutionState SolutionState => CompilationState.SolutionState; - internal SolutionCompilationState CompilationState => _compilationState; + internal SolutionCompilationState CompilationState { get; } internal int WorkspaceVersion => this.SolutionState.WorkspaceVersion; - internal bool PartialSemanticsEnabled => _compilationState.PartialSemanticsEnabled; + internal bool PartialSemanticsEnabled => CompilationState.PartialSemanticsEnabled; /// /// Per solution services provided by the host environment. Use this instead of internal ProjectId? GetOriginatingProjectId(ISymbol symbol) - => _compilationState.GetOriginatingProjectInfo(symbol)?.ProjectId; + => CompilationState.GetOriginatingProjectInfo(symbol)?.ProjectId; /// internal Project? GetOriginatingProject(ISymbol symbol) @@ -202,7 +202,7 @@ private static Project CreateProject(ProjectId projectId, Solution solution) /// this will be the compilation it was retargtted into, not the original compilation that it was retargetted from. /// internal Compilation? GetOriginatingCompilation(ISymbol symbol) - => _compilationState.GetOriginatingProjectInfo(symbol)?.Compilation; + => CompilationState.GetOriginatingProjectInfo(symbol)?.Compilation; /// /// True if the solution contains the document in one of its projects @@ -228,7 +228,7 @@ private static Project CreateProject(ProjectId projectId, Solution solution) /// Gets the documentId in this solution with the specified syntax tree. /// public DocumentId? GetDocumentId(SyntaxTree? syntaxTree, ProjectId? projectId) - => _compilationState.GetDocumentState(syntaxTree, projectId)?.Id; + => CompilationState.GetDocumentState(syntaxTree, projectId)?.Id; /// /// Gets the document in this solution with the specified document ID. @@ -316,7 +316,7 @@ private static Project CreateProject(ProjectId projectId, Solution solution) { if (syntaxTree != null) { - var documentState = _compilationState.GetDocumentState(syntaxTree, projectId); + var documentState = CompilationState.GetDocumentState(syntaxTree, projectId); if (documentState is SourceGeneratedDocumentState) { @@ -337,7 +337,7 @@ private static Project CreateProject(ProjectId projectId, Solution solution) } private Solution WithCompilationState(SolutionCompilationState compilationState) - => compilationState == _compilationState ? this : new Solution(compilationState); + => compilationState == CompilationState ? this : new Solution(compilationState); /// /// Creates a new solution instance that includes a project with the specified language and names. @@ -365,7 +365,7 @@ public Solution AddProject(ProjectInfo projectInfo) /// internal Solution AddProjects(ArrayBuilder projectInfos) - => WithCompilationState(_compilationState.AddProjects(projectInfos)); + => WithCompilationState(CompilationState.AddProjects(projectInfos)); /// public Solution RemoveProject(ProjectId projectId) @@ -377,7 +377,7 @@ public Solution RemoveProject(ProjectId projectId) /// internal Solution RemoveProjects(ArrayBuilder projectIds) - => WithCompilationState(_compilationState.RemoveProjects(projectIds)); + => WithCompilationState(CompilationState.RemoveProjects(projectIds)); /// /// Creates a new solution instance with the project specified updated to have the new @@ -392,7 +392,7 @@ public Solution WithProjectAssemblyName(ProjectId projectId, string assemblyName throw new ArgumentNullException(nameof(assemblyName)); } - return WithCompilationState(_compilationState.WithProjectAssemblyName(projectId, assemblyName)); + return WithCompilationState(CompilationState.WithProjectAssemblyName(projectId, assemblyName)); } /// @@ -402,7 +402,7 @@ public Solution WithProjectOutputFilePath(ProjectId projectId, string? outputFil { CheckContainsProject(projectId); - return WithCompilationState(_compilationState.WithProjectOutputFilePath(projectId, outputFilePath)); + return WithCompilationState(CompilationState.WithProjectOutputFilePath(projectId, outputFilePath)); } /// @@ -412,7 +412,7 @@ public Solution WithProjectOutputRefFilePath(ProjectId projectId, string? output { CheckContainsProject(projectId); - return WithCompilationState(_compilationState.WithProjectOutputRefFilePath(projectId, outputRefFilePath)); + return WithCompilationState(CompilationState.WithProjectOutputRefFilePath(projectId, outputRefFilePath)); } /// @@ -422,7 +422,7 @@ public Solution WithProjectCompilationOutputInfo(ProjectId projectId, in Compila { CheckContainsProject(projectId); - return WithCompilationState(_compilationState.WithProjectCompilationOutputInfo(projectId, info)); + return WithCompilationState(CompilationState.WithProjectCompilationOutputInfo(projectId, info)); } /// @@ -432,7 +432,7 @@ public Solution WithProjectDefaultNamespace(ProjectId projectId, string? default { CheckContainsProject(projectId); - return WithCompilationState(_compilationState.WithProjectDefaultNamespace(projectId, defaultNamespace)); + return WithCompilationState(CompilationState.WithProjectDefaultNamespace(projectId, defaultNamespace)); } /// @@ -442,7 +442,7 @@ internal Solution WithProjectChecksumAlgorithm(ProjectId projectId, SourceHashAl { CheckContainsProject(projectId); - return WithCompilationState(_compilationState.WithProjectChecksumAlgorithm(projectId, checksumAlgorithm)); + return WithCompilationState(CompilationState.WithProjectChecksumAlgorithm(projectId, checksumAlgorithm)); } /// @@ -457,7 +457,7 @@ public Solution WithProjectName(ProjectId projectId, string name) throw new ArgumentNullException(nameof(name)); } - return WithCompilationState(_compilationState.WithProjectName(projectId, name)); + return WithCompilationState(CompilationState.WithProjectName(projectId, name)); } /// @@ -467,7 +467,7 @@ public Solution WithProjectFilePath(ProjectId projectId, string? filePath) { CheckContainsProject(projectId); - return WithCompilationState(_compilationState.WithProjectFilePath(projectId, filePath)); + return WithCompilationState(CompilationState.WithProjectFilePath(projectId, filePath)); } /// @@ -483,7 +483,7 @@ public Solution WithProjectCompilationOptions(ProjectId projectId, CompilationOp throw new ArgumentNullException(nameof(options)); } - return WithCompilationState(_compilationState.WithProjectCompilationOptions(projectId, options)); + return WithCompilationState(CompilationState.WithProjectCompilationOptions(projectId, options)); } /// @@ -499,14 +499,14 @@ public Solution WithProjectParseOptions(ProjectId projectId, ParseOptions option throw new ArgumentNullException(nameof(options)); } - return WithCompilationState(_compilationState.WithProjectParseOptions(projectId, options)); + return WithCompilationState(CompilationState.WithProjectParseOptions(projectId, options)); } /// /// Create a new solution instance updated to use the specified . /// internal Solution WithFallbackAnalyzerOptions(ImmutableDictionary options) - => WithCompilationState(_compilationState.WithFallbackAnalyzerOptions(options)); + => WithCompilationState(CompilationState.WithFallbackAnalyzerOptions(options)); /// /// Create a new solution instance with the project specified updated to have @@ -517,7 +517,7 @@ internal Solution WithHasAllInformation(ProjectId projectId, bool hasAllInformat { CheckContainsProject(projectId); - return WithCompilationState(_compilationState.WithHasAllInformation(projectId, hasAllInformation)); + return WithCompilationState(CompilationState.WithHasAllInformation(projectId, hasAllInformation)); } /// @@ -529,7 +529,7 @@ internal Solution WithRunAnalyzers(ProjectId projectId, bool runAnalyzers) { CheckContainsProject(projectId); - return WithCompilationState(_compilationState.WithRunAnalyzers(projectId, runAnalyzers)); + return WithCompilationState(CompilationState.WithRunAnalyzers(projectId, runAnalyzers)); } /// @@ -550,7 +550,25 @@ public Solution WithProjectDocumentsOrder(ProjectId projectId, ImmutableList + /// Updates the solution with project information stored in . + /// + internal Solution WithProjectAttributes(ProjectInfo.ProjectAttributes attributes) + { + CheckContainsProject(attributes.Id); + return WithCompilationState(CompilationState.WithProjectAttributes(attributes)); + } + + /// + /// Updates the solution with project information stored in . + /// + internal Solution WithProjectInfo(ProjectInfo info) + { + CheckContainsProject(info.Id); + return WithCompilationState(CompilationState.WithProjectInfo(info)); } /// @@ -597,7 +615,7 @@ public Solution AddProjectReferences(ProjectId projectId, IEnumerable @@ -609,16 +627,23 @@ public Solution AddProjectReferences(ProjectId projectId, IEnumerableThe solution does not contain . public Solution RemoveProjectReference(ProjectId projectId, ProjectReference projectReference) { - if (projectReference == null) - throw new ArgumentNullException(nameof(projectReference)); + try + { + if (projectReference == null) + throw new ArgumentNullException(nameof(projectReference)); - CheckContainsProject(projectId); + CheckContainsProject(projectId); - var oldProject = GetRequiredProjectState(projectId); - if (!oldProject.ProjectReferences.Contains(projectReference)) - throw new ArgumentException(WorkspacesResources.Project_does_not_contain_specified_reference, nameof(projectReference)); + var oldProject = GetRequiredProjectState(projectId); + if (!oldProject.ProjectReferences.Contains(projectReference)) + throw new ArgumentException(WorkspacesResources.Project_does_not_contain_specified_reference, nameof(projectReference)); - return WithCompilationState(_compilationState.RemoveProjectReference(projectId, projectReference)); + return WithCompilationState(CompilationState.RemoveProjectReference(projectId, projectReference)); + } + catch (Exception ex) when (FatalError.ReportAndPropagate(ex)) + { + throw ExceptionUtilities.Unreachable(); + } } /// @@ -641,7 +666,7 @@ public Solution WithProjectReferences(ProjectId projectId, IEnumerable @@ -683,7 +708,7 @@ public Solution AddMetadataReferences(ProjectId projectId, IEnumerable @@ -705,7 +730,7 @@ public Solution RemoveMetadataReference(ProjectId projectId, MetadataReference m if (!oldProject.MetadataReferences.Contains(metadataReference)) throw new InvalidOperationException(WorkspacesResources.Project_does_not_contain_specified_reference); - return WithCompilationState(_compilationState.RemoveMetadataReference(projectId, metadataReference)); + return WithCompilationState(CompilationState.RemoveMetadataReference(projectId, metadataReference)); } /// @@ -722,7 +747,7 @@ public Solution WithProjectMetadataReferences(ProjectId projectId, IEnumerable @@ -768,7 +793,7 @@ public Solution AddAnalyzerReferences(ProjectId projectId, IEnumerable @@ -790,7 +815,7 @@ public Solution RemoveAnalyzerReference(ProjectId projectId, AnalyzerReference a if (!oldProject.AnalyzerReferences.Contains(analyzerReference)) throw new InvalidOperationException(WorkspacesResources.Project_does_not_contain_specified_reference); - return WithCompilationState(_compilationState.RemoveAnalyzerReference(projectId, analyzerReference)); + return WithCompilationState(CompilationState.RemoveAnalyzerReference(projectId, analyzerReference)); } /// @@ -807,7 +832,7 @@ public Solution WithProjectAnalyzerReferences(ProjectId projectId, IEnumerable @@ -841,7 +866,7 @@ public Solution AddAnalyzerReferences(IEnumerable analyzerRef } } - return WithCompilationState(_compilationState.AddAnalyzerReferences(collection)); + return WithCompilationState(CompilationState.AddAnalyzerReferences(collection)); } /// @@ -858,7 +883,7 @@ public Solution RemoveAnalyzerReference(AnalyzerReference analyzerReference) if (!this.SolutionState.AnalyzerReferences.Contains(analyzerReference)) throw new InvalidOperationException(WorkspacesResources.Solution_does_not_contain_specified_reference); - return WithCompilationState(_compilationState.RemoveAnalyzerReference(analyzerReference)); + return WithCompilationState(CompilationState.RemoveAnalyzerReference(analyzerReference)); } /// @@ -870,7 +895,7 @@ public Solution WithAnalyzerReferences(IEnumerable analyzerRe { var collection = PublicContract.ToBoxedImmutableArrayWithDistinctNonNullItems(analyzerReferences, nameof(analyzerReferences)); - return WithCompilationState(_compilationState.WithAnalyzerReferences(collection)); + return WithCompilationState(CompilationState.WithAnalyzerReferences(collection)); } private static SourceCodeKind GetSourceCodeKind(ProjectState project) @@ -983,7 +1008,7 @@ public Solution AddDocument(DocumentInfo documentInfo) /// /// A new with the documents added. public Solution AddDocuments(ImmutableArray documentInfos) - => WithCompilationState(_compilationState.AddDocuments(documentInfos)); + => WithCompilationState(CompilationState.AddDocumentsToMultipleProjects(documentInfos)); /// /// Creates a new solution instance with the corresponding project updated to include a new @@ -1021,7 +1046,7 @@ public Solution AddAdditionalDocument(DocumentInfo documentInfo) => AddAdditionalDocuments([documentInfo]); public Solution AddAdditionalDocuments(ImmutableArray documentInfos) - => WithCompilationState(_compilationState.AddAdditionalDocuments(documentInfos)); + => WithCompilationState(CompilationState.AddDocumentsToMultipleProjects(documentInfos)); /// /// Creates a new solution instance with the corresponding project updated to include a new @@ -1066,14 +1091,14 @@ private DocumentInfo CreateDocumentInfo(DocumentId documentId, string name, Sour filePath: filePath); } - private ProjectState GetRequiredProjectState(ProjectId projectId) + internal ProjectState GetRequiredProjectState(ProjectId projectId) => this.SolutionState.GetProjectState(projectId) ?? throw new InvalidOperationException(string.Format(WorkspacesResources._0_is_not_part_of_the_workspace, projectId)); /// /// Creates a new Solution instance that contains a new compiler configuration document like a .editorconfig file. /// public Solution AddAnalyzerConfigDocuments(ImmutableArray documentInfos) - => WithCompilationState(_compilationState.AddAnalyzerConfigDocuments(documentInfos)); + => WithCompilationState(CompilationState.AddDocumentsToMultipleProjects(documentInfos)); /// /// Creates a new solution instance that no longer includes the specified document. @@ -1094,7 +1119,7 @@ public Solution RemoveDocuments(ImmutableArray documentIds) } private Solution RemoveDocumentsImpl(ImmutableArray documentIds) - => WithCompilationState(_compilationState.RemoveDocuments(documentIds)); + => WithCompilationState(CompilationState.RemoveDocumentsFromMultipleProjects(documentIds)); /// /// Creates a new solution instance that no longer includes the specified additional document. @@ -1115,7 +1140,7 @@ public Solution RemoveAdditionalDocuments(ImmutableArray documentIds } private Solution RemoveAdditionalDocumentsImpl(ImmutableArray documentIds) - => WithCompilationState(_compilationState.RemoveAdditionalDocuments(documentIds)); + => WithCompilationState(CompilationState.RemoveDocumentsFromMultipleProjects(documentIds)); /// /// Creates a new solution instance that no longer includes the specified . @@ -1136,7 +1161,7 @@ public Solution RemoveAnalyzerConfigDocuments(ImmutableArray documen } private Solution RemoveAnalyzerConfigDocumentsImpl(ImmutableArray documentIds) - => WithCompilationState(_compilationState.RemoveAnalyzerConfigDocuments(documentIds)); + => WithCompilationState(CompilationState.RemoveDocumentsFromMultipleProjects(documentIds)); /// /// Creates a new solution instance with the document specified updated to have the new name. @@ -1150,7 +1175,10 @@ public Solution WithDocumentName(DocumentId documentId, string name) throw new ArgumentNullException(nameof(name)); } - return WithCompilationState(_compilationState.WithDocumentName(documentId, name)); + return WithCompilationState(CompilationState.WithDocumentAttributes( + documentId, + name, + static (attributes, value) => attributes.With(name: value))); } /// @@ -1163,7 +1191,10 @@ public Solution WithDocumentFolders(DocumentId documentId, IEnumerable? var collection = PublicContract.ToBoxedImmutableArrayWithNonNullItems(folders, nameof(folders)); - return WithCompilationState(_compilationState.WithDocumentFolders(documentId, collection)); + return WithCompilationState(CompilationState.WithDocumentAttributes( + documentId, + collection, + static (attributes, value) => attributes.With(folders: value))); } /// @@ -1172,7 +1203,11 @@ public Solution WithDocumentFolders(DocumentId documentId, IEnumerable? public Solution WithDocumentFilePath(DocumentId documentId, string? filePath) { CheckContainsDocument(documentId); - return WithCompilationState(_compilationState.WithDocumentFilePath(documentId, filePath)); + + return WithCompilationState(CompilationState.WithDocumentAttributes( + documentId, + filePath, + static (attributes, value) => attributes.With(filePath: value))); } /// @@ -1195,7 +1230,7 @@ internal Solution WithDocumentTexts(ImmutableArray<(DocumentId documentId, Sourc throw new ArgumentOutOfRangeException(nameof(mode)); } - return WithCompilationState(_compilationState.WithDocumentTexts(texts, mode)); + return WithCompilationState(CompilationState.WithDocumentTexts(texts, mode)); } /// @@ -1216,7 +1251,7 @@ public Solution WithAdditionalDocumentText(DocumentId documentId, SourceText tex throw new ArgumentOutOfRangeException(nameof(mode)); } - return WithCompilationState(_compilationState.WithAdditionalDocumentText(documentId, text, mode)); + return WithCompilationState(CompilationState.WithAdditionalDocumentText(documentId, text, mode)); } /// @@ -1237,7 +1272,7 @@ public Solution WithAnalyzerConfigDocumentText(DocumentId documentId, SourceText throw new ArgumentOutOfRangeException(nameof(mode)); } - return WithCompilationState(_compilationState.WithAnalyzerConfigDocumentText(documentId, text, mode)); + return WithCompilationState(CompilationState.WithAnalyzerConfigDocumentText(documentId, text, mode)); } /// @@ -1258,7 +1293,7 @@ public Solution WithDocumentText(DocumentId documentId, TextAndVersion textAndVe throw new ArgumentOutOfRangeException(nameof(mode)); } - return WithCompilationState(_compilationState.WithDocumentText(documentId, textAndVersion, mode)); + return WithCompilationState(CompilationState.WithDocumentText(documentId, textAndVersion, mode)); } /// @@ -1279,7 +1314,7 @@ public Solution WithAdditionalDocumentText(DocumentId documentId, TextAndVersion throw new ArgumentOutOfRangeException(nameof(mode)); } - return WithCompilationState(_compilationState.WithAdditionalDocumentText(documentId, textAndVersion, mode)); + return WithCompilationState(CompilationState.WithAdditionalDocumentText(documentId, textAndVersion, mode)); } /// @@ -1300,7 +1335,7 @@ public Solution WithAnalyzerConfigDocumentText(DocumentId documentId, TextAndVer throw new ArgumentOutOfRangeException(nameof(mode)); } - return WithCompilationState(_compilationState.WithAnalyzerConfigDocumentText(documentId, textAndVersion, mode)); + return WithCompilationState(CompilationState.WithAnalyzerConfigDocumentText(documentId, textAndVersion, mode)); } /// @@ -1324,14 +1359,14 @@ internal Solution WithDocumentSyntaxRoots(ImmutableArray<(DocumentId documentId, throw new ArgumentNullException(nameof(root)); } - return WithCompilationState(_compilationState.WithDocumentSyntaxRoots(syntaxRoots, mode)); + return WithCompilationState(CompilationState.WithDocumentSyntaxRoots(syntaxRoots, mode)); } internal Solution WithDocumentContentsFrom(DocumentId documentId, DocumentState documentState, bool forceEvenIfTreesWouldDiffer) - => WithCompilationState(_compilationState.WithDocumentContentsFrom([(documentId, documentState)], forceEvenIfTreesWouldDiffer)); + => WithCompilationState(CompilationState.WithDocumentContentsFrom([(documentId, documentState)], forceEvenIfTreesWouldDiffer)); internal Solution WithDocumentContentsFrom(ImmutableArray<(DocumentId documentId, DocumentState documentState)> documentIdsAndStates, bool forceEvenIfTreesWouldDiffer) - => WithCompilationState(_compilationState.WithDocumentContentsFrom(documentIdsAndStates, forceEvenIfTreesWouldDiffer)); + => WithCompilationState(CompilationState.WithDocumentContentsFrom(documentIdsAndStates, forceEvenIfTreesWouldDiffer)); /// /// Creates a new solution instance with the document specified updated to have the source @@ -1353,7 +1388,7 @@ public Solution WithDocumentSourceCodeKind(DocumentId documentId, SourceCodeKind throw new ArgumentOutOfRangeException(nameof(sourceCodeKind)); } - return WithCompilationState(_compilationState.WithDocumentSourceCodeKind(documentId, sourceCodeKind)); + return WithCompilationState(CompilationState.WithDocumentSourceCodeKind(documentId, sourceCodeKind)); } /// @@ -1374,7 +1409,7 @@ public Solution WithDocumentTextLoader(DocumentId documentId, TextLoader loader, throw new ArgumentOutOfRangeException(nameof(mode)); } - return WithCompilationState(_compilationState.UpdateDocumentTextLoader(documentId, loader, mode)); + return WithCompilationState(CompilationState.UpdateDocumentTextLoader(documentId, loader, mode)); } /// @@ -1395,7 +1430,7 @@ public Solution WithAdditionalDocumentTextLoader(DocumentId documentId, TextLoad throw new ArgumentOutOfRangeException(nameof(mode)); } - return WithCompilationState(_compilationState.UpdateAdditionalDocumentTextLoader(documentId, loader, mode)); + return WithCompilationState(CompilationState.UpdateAdditionalDocumentTextLoader(documentId, loader, mode)); } /// @@ -1416,7 +1451,7 @@ public Solution WithAnalyzerConfigDocumentTextLoader(DocumentId documentId, Text throw new ArgumentOutOfRangeException(nameof(mode)); } - return WithCompilationState(_compilationState.UpdateAnalyzerConfigDocumentTextLoader(documentId, loader, mode)); + return WithCompilationState(CompilationState.UpdateAnalyzerConfigDocumentTextLoader(documentId, loader, mode)); } /// @@ -1517,7 +1552,7 @@ internal ImmutableArray GetRelatedDocumentIds(DocumentId documentId) => this.SolutionState.GetFirstRelatedDocumentId(documentId, relatedProjectIdHint); internal Solution WithNewWorkspace(string? workspaceKind, int workspaceVersion, SolutionServices services) - => WithCompilationState(_compilationState.WithNewWorkspace(workspaceKind, workspaceVersion, services)); + => WithCompilationState(CompilationState.WithNewWorkspace(workspaceKind, workspaceVersion, services)); /// /// Formerly, returned a copy of the solution isolated from the original so that they do not share computed state. It now does nothing. @@ -1550,7 +1585,7 @@ public Solution WithDocumentText(IEnumerable documentIds, SourceTex throw new ArgumentOutOfRangeException(nameof(mode)); } - return WithCompilationState(_compilationState.WithDocumentText(documentIds, text, mode)); + return WithCompilationState(CompilationState.WithDocumentText(documentIds, text, mode)); } /// @@ -1561,7 +1596,7 @@ public Solution WithDocumentText(IEnumerable documentIds, SourceTex internal Document WithFrozenSourceGeneratedDocument( SourceGeneratedDocumentIdentity documentIdentity, DateTime generationDateTime, SourceText text) { - var newCompilationState = _compilationState.WithFrozenSourceGeneratedDocuments([(documentIdentity, generationDateTime, text)]); + var newCompilationState = CompilationState.WithFrozenSourceGeneratedDocuments([(documentIdentity, generationDateTime, text)]); var newSolution = WithCompilationState(newCompilationState); var newDocumentState = newCompilationState.TryGetSourceGeneratedDocumentStateForAlreadyGeneratedId(documentIdentity.DocumentId); @@ -1572,18 +1607,18 @@ internal Document WithFrozenSourceGeneratedDocument( } internal Solution WithFrozenSourceGeneratedDocuments(ImmutableArray<(SourceGeneratedDocumentIdentity documentIdentity, DateTime generationDateTime, SourceText text)> documents) - => WithCompilationState(_compilationState.WithFrozenSourceGeneratedDocuments(documents)); + => WithCompilationState(CompilationState.WithFrozenSourceGeneratedDocuments(documents)); /// internal Solution UpdateSpecificSourceGeneratorExecutionVersions(SourceGeneratorExecutionVersionMap sourceGeneratorExecutionVersionMap) - => WithCompilationState(_compilationState.UpdateSpecificSourceGeneratorExecutionVersions(sourceGeneratorExecutionVersionMap)); + => WithCompilationState(CompilationState.UpdateSpecificSourceGeneratorExecutionVersions(sourceGeneratorExecutionVersionMap)); /// /// Undoes the operation of ; any frozen source generated document is allowed /// to have it's real output again. /// internal Solution WithoutFrozenSourceGeneratedDocuments() - => WithCompilationState(_compilationState.WithoutFrozenSourceGeneratedDocuments()); + => WithCompilationState(CompilationState.WithoutFrozenSourceGeneratedDocuments()); /// /// Returns a new Solution which represents the same state as before, but with the cached generator driver state from the given project updated to match. @@ -1594,7 +1629,7 @@ internal Solution WithoutFrozenSourceGeneratedDocuments() /// the cached state. /// internal Solution WithCachedSourceGeneratorState(ProjectId projectToUpdate, Project projectWithCachedGeneratorState) - => WithCompilationState(_compilationState.WithCachedSourceGeneratorState(projectToUpdate, projectWithCachedGeneratorState)); + => WithCompilationState(CompilationState.WithCachedSourceGeneratorState(projectToUpdate, projectWithCachedGeneratorState)); /// /// Gets an objects that lists the added, changed and removed projects between @@ -1657,7 +1692,7 @@ public Solution WithOptions(OptionSet options) /// Creates a new solution instance with the specified serializable . /// internal Solution WithOptions(SolutionOptionSet options) - => WithCompilationState(_compilationState.WithOptions(options)); + => WithCompilationState(CompilationState.WithOptions(options)); private void CheckContainsProject(ProjectId projectId) { diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.CompilationTracker.CompilationTrackerState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.CompilationTracker.CompilationTrackerState.cs index 2b704cf822af2..7e21d3405ecc9 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.CompilationTracker.CompilationTrackerState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.CompilationTracker.CompilationTrackerState.cs @@ -72,7 +72,7 @@ private sealed class InProgressState : CompilationTrackerState /// correct snapshot in that the generators have not been rerun, but may be reusable if the generators /// are later found to give the same output. /// - public readonly Lazy LazyStaleCompilationWithGeneratedDocuments; + public readonly CancellableLazy LazyStaleCompilationWithGeneratedDocuments; /// /// The list of changes that have happened since we last computed a compilation. The oldState corresponds to @@ -86,7 +86,7 @@ public InProgressState( CreationPolicy creationPolicy, Lazy compilationWithoutGeneratedDocuments, CompilationTrackerGeneratorInfo generatorInfo, - Lazy staleCompilationWithGeneratedDocuments, + CancellableLazy staleCompilationWithGeneratedDocuments, ImmutableList pendingTranslationActions) : base(creationPolicy, generatorInfo) { @@ -123,8 +123,8 @@ public InProgressState( { } - private static Lazy CreateLazyCompilation(Compilation? staleCompilationWithGeneratedDocuments) - => new(() => staleCompilationWithGeneratedDocuments); + private static CancellableLazy CreateLazyCompilation(Compilation? staleCompilationWithGeneratedDocuments) + => new(staleCompilationWithGeneratedDocuments); } /// diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs index 21e53564084df..1b3ad30d20649 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.ICompilationTracker.cs @@ -49,7 +49,7 @@ bool ContainsAssemblyOrModuleOrDynamic( /// /// Updates the creation policy for this tracker. Setting it to . /// - ICompilationTracker WithDoNotCreateCreationPolicy(CancellationToken cancellationToken); + ICompilationTracker WithDoNotCreateCreationPolicy(); Task GetDependentVersionAsync(SolutionCompilationState compilationState, CancellationToken cancellationToken); Task GetDependentSemanticVersionAsync(SolutionCompilationState compilationState, CancellationToken cancellationToken); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker.cs index e2917700d9427..98fb08ccbf46c 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker.cs @@ -32,7 +32,7 @@ private sealed partial class RegularCompilationTracker : ICompilationTracker private static readonly Func s_logBuildCompilationAsync = state => string.Join(",", state.AssemblyName, state.DocumentStates.Count); - private static readonly Lazy s_lazyNullCompilation = new Lazy(() => null); + private static readonly CancellableLazy s_lazyNullCompilation = new CancellableLazy((Compilation?)null); public ProjectState ProjectState { get; } @@ -145,7 +145,7 @@ public ICompilationTracker Fork( var (compilationWithoutGeneratedDocuments, staleCompilationWithGeneratedDocuments) = state switch { InProgressState inProgressState => (inProgressState.LazyCompilationWithoutGeneratedDocuments, inProgressState.LazyStaleCompilationWithGeneratedDocuments), - FinalCompilationTrackerState finalState => (new Lazy(() => finalState.CompilationWithoutGeneratedDocuments), new Lazy(() => finalState.FinalCompilationWithGeneratedDocuments)), + FinalCompilationTrackerState finalState => (new Lazy(() => finalState.CompilationWithoutGeneratedDocuments), new CancellableLazy(finalState.FinalCompilationWithGeneratedDocuments)), _ => throw ExceptionUtilities.UnexpectedValue(state.GetType()), }; @@ -404,7 +404,7 @@ async Task CollapseInProgressStateAsync(InProgressState initial var translationAction = inProgressState.PendingTranslationActions[0]; var compilationWithoutGeneratedDocuments = inProgressState.CompilationWithoutGeneratedDocuments; - var staleCompilationWithGeneratedDocuments = inProgressState.LazyStaleCompilationWithGeneratedDocuments.Value; + var staleCompilationWithGeneratedDocuments = inProgressState.LazyStaleCompilationWithGeneratedDocuments.GetValue(cancellationToken); // If staleCompilationWithGeneratedDocuments is the same as compilationWithoutGeneratedDocuments, // then it means a prior run of generators didn't produce any files. In that case, we'll just make @@ -476,7 +476,7 @@ async Task FinalizeCompilationWorkerAsync(InProgre var creationPolicy = inProgressState.CreationPolicy; var generatorInfo = inProgressState.GeneratorInfo; var compilationWithoutGeneratedDocuments = inProgressState.CompilationWithoutGeneratedDocuments; - var staleCompilationWithGeneratedDocuments = inProgressState.LazyStaleCompilationWithGeneratedDocuments.Value; + var staleCompilationWithGeneratedDocuments = inProgressState.LazyStaleCompilationWithGeneratedDocuments.GetValue(cancellationToken); // Project is complete only if the following are all true: // 1. HasAllInformation flag is set for the project @@ -735,7 +735,7 @@ public ICompilationTracker WithCreateCreationPolicy(bool forceRegeneration) skeletonReferenceCacheToClone: _skeletonReferenceCache); } - public ICompilationTracker WithDoNotCreateCreationPolicy(CancellationToken cancellationToken) + public ICompilationTracker WithDoNotCreateCreationPolicy() { var state = this.ReadState(); @@ -792,8 +792,7 @@ public ICompilationTracker WithDoNotCreateCreationPolicy(CancellationToken cance var alreadyParsedTrees = alreadyParsedTreesBuilder.ToImmutableAndClear(); var lazyCompilationWithoutGeneratedDocuments = new Lazy(() => this.CreateEmptyCompilation().AddSyntaxTrees(alreadyParsedTrees)); - // Safe cast to appease NRT system. - var lazyCompilationWithGeneratedDocuments = (Lazy)lazyCompilationWithoutGeneratedDocuments!; + var lazyCompilationWithGeneratedDocuments = new CancellableLazy(cancellationToken => lazyCompilationWithoutGeneratedDocuments.Value); return new RegularCompilationTracker( frozenProjectState, @@ -818,8 +817,12 @@ public ICompilationTracker WithDoNotCreateCreationPolicy(CancellationToken cance // us to a frozen state with that information. var generatorInfo = inProgressState.GeneratorInfo; var compilationWithoutGeneratedDocuments = inProgressState.LazyCompilationWithoutGeneratedDocuments; - var compilationWithGeneratedDocuments = new Lazy(() => compilationWithoutGeneratedDocuments.Value.AddSyntaxTrees( - generatorInfo.Documents.States.Values.Select(state => state.GetSyntaxTree(cancellationToken)))); + + var compilationWithGeneratedDocuments = new CancellableLazy(cancellationToken => + { + var syntaxTrees = generatorInfo.Documents.States.Values.Select(state => state.GetSyntaxTree(cancellationToken)); + return compilationWithoutGeneratedDocuments.Value.AddSyntaxTrees(syntaxTrees); + }); return new RegularCompilationTracker( frozenProjectState, @@ -872,7 +875,7 @@ public async ValueTask> GetSourceGeneratorDiagnostics foreach (var result in driverRunResult.Results) { - if (!IsGeneratorRunResultToIgnore(result)) + if (!result.Diagnostics.IsDefaultOrEmpty) { builder.AddRange(result.Diagnostics); } @@ -902,42 +905,12 @@ public async ValueTask> GetSourceGeneratorDiagnostics return state is FinalCompilationTrackerState finalState ? finalState.GeneratorInfo.Documents.GetState(documentId) : null; } - // HACK HACK HACK HACK around a problem introduced by https://github.com/dotnet/sdk/pull/24928. The Razor generator is - // controlled by a flag that lives in an .editorconfig file; in the IDE we generally don't run the generator and instead use - // the design-time files added through the legacy IDynamicFileInfo API. When we're doing Hot Reload we then - // remove those legacy files and remove the .editorconfig file that is supposed to disable the generator, for the Hot - // Reload pass we then are running the generator. This is done in the CompileTimeSolutionProvider. - // - // https://github.com/dotnet/sdk/pull/24928 introduced an issue where even though the Razor generator is being told to not - // run, it still runs anyways. As a tactical fix rather than reverting that PR, for Visual Studio 17.3 Preview 2 we are going - // to do a hack here which is to rip out generated files. - - private bool IsGeneratorRunResultToIgnore(GeneratorRunResult result) - { - var globalOptions = this.ProjectState.AnalyzerOptions.AnalyzerConfigOptionsProvider.GlobalOptions; - - // This matches the implementation in https://github.com/chsienki/sdk/blob/4696442a24e3972417fb9f81f182420df0add107/src/RazorSdk/SourceGenerators/RazorSourceGenerator.RazorProviders.cs#L27-L28 - var suppressGenerator = globalOptions.TryGetValue("build_property.SuppressRazorSourceGenerator", out var option) && option == "true"; - - if (!suppressGenerator) - return false; - - var generatorType = result.Generator.GetGeneratorType(); - return generatorType.FullName == "Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator" && - generatorType.Assembly.GetName().Name is "Microsoft.NET.Sdk.Razor.SourceGenerators" or - "Microsoft.CodeAnalysis.Razor.Compiler.SourceGenerators" or - "Microsoft.CodeAnalysis.Razor.Compiler"; - } - public SkeletonReferenceCache GetClonedSkeletonReferenceCache() => _skeletonReferenceCache.Clone(); public Task GetOrBuildSkeletonReferenceAsync(SolutionCompilationState compilationState, MetadataReferenceProperties properties, CancellationToken cancellationToken) => _skeletonReferenceCache.GetOrBuildReferenceAsync(this, compilationState, properties, cancellationToken); - // END HACK HACK HACK HACK, or the setup of it at least; once this hack is removed the calls to IsGeneratorRunResultToIgnore - // need to be cleaned up. - /// /// Validates the compilation is consistent and we didn't have a bug in producing it. This only runs under a feature flag. /// @@ -961,9 +934,9 @@ private void ValidateState(CompilationTrackerState? state) ValidateCompilationTreesMatchesProjectState(inProgressState.CompilationWithoutGeneratedDocuments, projectState, generatorInfo: null); - if (inProgressState.LazyStaleCompilationWithGeneratedDocuments.Value != null) + if (inProgressState.LazyStaleCompilationWithGeneratedDocuments.GetValue(CancellationToken.None) is Compilation staleCompilationWithGeneratedDocuments) { - ValidateCompilationTreesMatchesProjectState(inProgressState.LazyStaleCompilationWithGeneratedDocuments.Value, projectState, inProgressState.GeneratorInfo); + ValidateCompilationTreesMatchesProjectState(staleCompilationWithGeneratedDocuments, projectState, inProgressState.GeneratorInfo); } } else diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker_Generators.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker_Generators.cs index c4e614fa3cc3e..366d9f75aeac4 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker_Generators.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.RegularCompilationTracker_Generators.cs @@ -282,7 +282,7 @@ await newGeneratedDocuments.States.Values.SelectAsArrayAsync( if (compilationWithStaleGeneratedTrees != null) { var generatedTreeCount = - runResult.Results.Sum(r => IsGeneratorRunResultToIgnore(r) ? 0 : r.GeneratedSources.Length); + runResult.Results.Sum(r => r.GeneratedSources.IsDefaultOrEmpty ? 0 : r.GeneratedSources.Length); if (oldGeneratedDocuments.Count != generatedTreeCount) compilationWithStaleGeneratedTrees = null; @@ -294,9 +294,6 @@ await newGeneratedDocuments.States.Values.SelectAsArrayAsync( var generationDateTime = DateTime.Now; foreach (var generatorResult in runResult.Results) { - if (IsGeneratorRunResultToIgnore(generatorResult)) - continue; - var generatorAnalyzerReference = GetAnalyzerReference(this.ProjectState, generatorResult.Generator); foreach (var generatedSource in generatorResult.GeneratedSources) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.SkeletonReferenceCache.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.SkeletonReferenceCache.cs index 2fbf3bc719d90..6b94ca42513af 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.SkeletonReferenceCache.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.SkeletonReferenceCache.cs @@ -260,7 +260,7 @@ public readonly SkeletonReferenceCache Clone() // Now read the data back from the stream from the memory mapped file. This will come back as an // UnmanagedMemoryStream, which our assembly/metadata subsystem is optimized around. var result = AssemblyMetadata.CreateFromStream( - handle.ReadFromTemporaryStorage(cancellationToken), leaveOpen: false); + handle.ReadFromTemporaryStorage(), leaveOpen: false); return (result, handle); } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.TranslationAction_Actions.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.TranslationAction_Actions.cs index 6d624d7c540f0..75056cd38afdb 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.TranslationAction_Actions.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.TranslationAction_Actions.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.Threading; @@ -20,15 +21,16 @@ private abstract partial class TranslationAction internal sealed class TouchDocumentsAction( ProjectState oldProjectState, ProjectState newProjectState, + ImmutableArray oldStates, ImmutableArray newStates) : TranslationAction(oldProjectState, newProjectState) { - private readonly ImmutableArray _oldStates = newStates.SelectAsArray(s => oldProjectState.DocumentStates.GetRequiredState(s.Id)); + private readonly ImmutableArray _oldStates = oldStates; private readonly ImmutableArray _newStates = newStates; public override async Task TransformCompilationAsync(Compilation oldCompilation, CancellationToken cancellationToken) { var finalCompilation = oldCompilation; - for (int i = 0, n = _newStates.Length; i < n; i++) + for (var i = 0; i < _newStates.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); var newState = _newStates[i]; @@ -57,22 +59,22 @@ public override GeneratorDriver TransformGeneratorDriver(GeneratorDriver generat { // As we're merging ourselves with the prior touch action, we want to keep the old project state // that we are translating from. - return new TouchDocumentsAction(priorAction.OldProjectState, this.NewProjectState, _newStates); + return new TouchDocumentsAction(priorAction.OldProjectState, NewProjectState, priorTouchAction._oldStates, _newStates); } return null; } } - internal sealed class TouchAdditionalDocumentAction( + internal sealed class TouchAdditionalDocumentsAction( ProjectState oldProjectState, ProjectState newProjectState, - AdditionalDocumentState oldState, - AdditionalDocumentState newState) + ImmutableArray oldStates, + ImmutableArray newStates) : TranslationAction(oldProjectState, newProjectState) { - private readonly AdditionalDocumentState _oldState = oldState; - private readonly AdditionalDocumentState _newState = newState; + private readonly ImmutableArray _oldStates = oldStates; + private readonly ImmutableArray _newStates = newStates; // Changing an additional document doesn't change the compilation directly, so we can "apply" the // translation (which is a no-op). Since we use a 'false' here to mean that it's not worth keeping the @@ -84,12 +86,12 @@ public override Task TransformCompilationAsync(Compilation oldCompi public override TranslationAction? TryMergeWithPrior(TranslationAction priorAction) { - if (priorAction is TouchAdditionalDocumentAction priorTouchAction && - priorTouchAction._newState == _oldState) + if (priorAction is TouchAdditionalDocumentsAction priorTouchAction && + priorTouchAction._newStates.SequenceEqual(_oldStates)) { // As we're merging ourselves with the prior touch action, we want to keep the old project state // that we are translating from. - return new TouchAdditionalDocumentAction(priorAction.OldProjectState, this.NewProjectState, priorTouchAction._oldState, _newState); + return new TouchAdditionalDocumentsAction(priorAction.OldProjectState, NewProjectState, priorTouchAction._oldStates, _newStates); } return null; @@ -97,13 +99,37 @@ public override Task TransformCompilationAsync(Compilation oldCompi public override GeneratorDriver TransformGeneratorDriver(GeneratorDriver generatorDriver) { - var oldText = _oldState.AdditionalText; - var newText = _newState.AdditionalText; + for (var i = 0; i < _newStates.Length; i++) + { + generatorDriver = generatorDriver.ReplaceAdditionalText(_oldStates[i].AdditionalText, _newStates[i].AdditionalText); + } - return generatorDriver.ReplaceAdditionalText(oldText, newText); + return generatorDriver; } } + internal sealed class TouchAnalyzerConfigDocumentsAction( + ProjectState oldProjectState, + ProjectState newProjectState) + : TranslationAction(oldProjectState, newProjectState) + { + /// + /// Updating editorconfig document updates . + /// + public override Task TransformCompilationAsync(Compilation oldCompilation, CancellationToken cancellationToken) + { + RoslynDebug.AssertNotNull(this.NewProjectState.CompilationOptions); + return Task.FromResult(oldCompilation.WithOptions(this.NewProjectState.CompilationOptions)); + } + + // Updating the analyzer config optons doesn't require us to reparse trees, so we can use this to update + // compilations with stale generated trees. + public override bool CanUpdateCompilationWithStaleGeneratedTreesIfGeneratorsGiveSameOutput => true; + + public override GeneratorDriver TransformGeneratorDriver(GeneratorDriver generatorDriver) + => generatorDriver.WithUpdatedAnalyzerConfigOptions(NewProjectState.AnalyzerOptions.AnalyzerConfigOptionsProvider); + } + internal sealed class RemoveDocumentsAction( ProjectState oldProjectState, ProjectState newProjectState, @@ -210,13 +236,11 @@ public override GeneratorDriver TransformGeneratorDriver(GeneratorDriver generat internal sealed class ProjectCompilationOptionsAction( ProjectState oldProjectState, - ProjectState newProjectState, - bool isAnalyzerConfigChange) - : TranslationAction(oldProjectState, newProjectState) + ProjectState newProjectState) : TranslationAction(oldProjectState, newProjectState) { public override Task TransformCompilationAsync(Compilation oldCompilation, CancellationToken cancellationToken) { - RoslynDebug.AssertNotNull(this.NewProjectState.CompilationOptions); + Contract.ThrowIfNull(this.NewProjectState.CompilationOptions); return Task.FromResult(oldCompilation.WithOptions(this.NewProjectState.CompilationOptions)); } @@ -226,16 +250,9 @@ public override Task TransformCompilationAsync(Compilation oldCompi public override GeneratorDriver TransformGeneratorDriver(GeneratorDriver generatorDriver) { - if (isAnalyzerConfigChange) - { - return generatorDriver.WithUpdatedAnalyzerConfigOptions(this.NewProjectState.AnalyzerOptions.AnalyzerConfigOptionsProvider); - } - else - { - // Changing any other option is fine and the driver can be reused. The driver - // will get the new compilation once we pass it to it. - return generatorDriver; - } + // Changing any other option is fine and the driver can be reused. The driver + // will get the new compilation once we pass it to it. + return generatorDriver; } } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs index d4c777ad64f9e..7db307dade635 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.WithFrozenSourceGeneratedDocumentsCompilationTracker.cs @@ -89,9 +89,9 @@ public ICompilationTracker WithCreateCreationPolicy(bool forceRegeneration) : new WithFrozenSourceGeneratedDocumentsCompilationTracker(underlyingTracker, _replacementDocumentStates); } - public ICompilationTracker WithDoNotCreateCreationPolicy(CancellationToken cancellationToken) + public ICompilationTracker WithDoNotCreateCreationPolicy() { - var underlyingTracker = this.UnderlyingTracker.WithDoNotCreateCreationPolicy(cancellationToken); + var underlyingTracker = this.UnderlyingTracker.WithDoNotCreateCreationPolicy(); return underlyingTracker == this.UnderlyingTracker ? this : new WithFrozenSourceGeneratedDocumentsCompilationTracker(underlyingTracker, _replacementDocumentStates); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs index 40a180c4c8e48..2ec5b6f14a04c 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs @@ -18,7 +18,6 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer; @@ -47,20 +46,6 @@ internal sealed partial class SolutionCompilationState // Values for all these are created on demand. private ImmutableSegmentedDictionary _projectIdToTrackerMap; - /// - /// Map from each project to the it is currently at. Loosely, the - /// execution version allows us to have the generated documents for a project get fixed at some point in the past - /// when they were generated, up until events happen in the host that cause a need for them to be brought up to - /// date. This is ambient, compilation-level, information about our projects, which is why it is stored at this - /// compilation-state level. When syncing to our OOP process, this information is included, allowing the oop side - /// to move its own generators forward when a host changes these versions. - /// - /// - /// Contains information for all projects, even non-C#/VB ones. Though this will have no meaning for those project - /// types. - /// - private readonly SourceGeneratorExecutionVersionMap _sourceGeneratorExecutionVersionMap; - /// /// Cache we use to map between unrooted symbols (i.e. assembly, module and dynamic symbols) and the project /// they came from. That way if we are asked about many symbols from the same assembly/module we can answer the @@ -82,7 +67,7 @@ private SolutionCompilationState( SolutionState = solution; PartialSemanticsEnabled = partialSemanticsEnabled; _projectIdToTrackerMap = projectIdToTrackerMap; - _sourceGeneratorExecutionVersionMap = sourceGeneratorExecutionVersionMap; + SourceGeneratorExecutionVersionMap = sourceGeneratorExecutionVersionMap; FrozenSourceGeneratedDocumentStates = frozenSourceGeneratedDocumentStates; // when solution state is changed, we recalculate its checksum @@ -124,7 +109,7 @@ private void CheckInvariants() // Solution and SG version maps must correspond to the same set of projects. Contract.ThrowIfFalse(this.SolutionState.ProjectStates .Select(kvp => kvp.Key) - .SetEquals(_sourceGeneratorExecutionVersionMap.Map.Keys)); + .SetEquals(SourceGeneratorExecutionVersionMap.Map.Keys)); } private SolutionCompilationState Branch( @@ -135,12 +120,12 @@ private SolutionCompilationState Branch( AsyncLazy? cachedFrozenSnapshot = null) { projectIdToTrackerMap ??= _projectIdToTrackerMap; - sourceGeneratorExecutionVersionMap ??= _sourceGeneratorExecutionVersionMap; + sourceGeneratorExecutionVersionMap ??= SourceGeneratorExecutionVersionMap; var newFrozenSourceGeneratedDocumentStates = frozenSourceGeneratedDocumentStates.HasValue ? frozenSourceGeneratedDocumentStates.Value : FrozenSourceGeneratedDocumentStates; if (newSolutionState == this.SolutionState && projectIdToTrackerMap == _projectIdToTrackerMap && - sourceGeneratorExecutionVersionMap == _sourceGeneratorExecutionVersionMap && + sourceGeneratorExecutionVersionMap == SourceGeneratorExecutionVersionMap && Equals(newFrozenSourceGeneratedDocumentStates, FrozenSourceGeneratedDocumentStates)) { return this; @@ -317,7 +302,19 @@ private ImmutableSegmentedDictionary CreateCompi return projectIdToTrackerMapBuilder.ToImmutable(); } - public SourceGeneratorExecutionVersionMap SourceGeneratorExecutionVersionMap => _sourceGeneratorExecutionVersionMap; + /// + /// Map from each project to the it is currently at. Loosely, the + /// execution version allows us to have the generated documents for a project get fixed at some point in the past + /// when they were generated, up until events happen in the host that cause a need for them to be brought up to + /// date. This is ambient, compilation-level, information about our projects, which is why it is stored at this + /// compilation-state level. When syncing to our OOP process, this information is included, allowing the oop side + /// to move its own generators forward when a host changes these versions. + /// + /// + /// Contains information for all projects, even non-C#/VB ones. Though this will have no meaning for those project + /// types. + /// + public SourceGeneratorExecutionVersionMap SourceGeneratorExecutionVersionMap { get; } /// public SolutionCompilationState AddProjects(ArrayBuilder projectInfos) @@ -347,7 +344,7 @@ public SolutionCompilationState AddProjects(ArrayBuilder projectInf // non-C#/VB projects. These will have no effect in-proc as we won't have compilation-trackers for these // projects. And, when communicating with the OOP process, we'll filter out these projects before sending them // across in SolutionCompilationState.GetFilteredSourceGenerationExecutionMap. - var versionMapBuilder = _sourceGeneratorExecutionVersionMap.Map.ToBuilder(); + var versionMapBuilder = SourceGeneratorExecutionVersionMap.Map.ToBuilder(); foreach (var projectInfo in projectInfos) versionMapBuilder.Add(projectInfo.Id, new()); @@ -394,7 +391,7 @@ public SolutionCompilationState RemoveProjects(ArrayBuilder projectId projectIds, skipEmptyCallback: true); - var versionMapBuilder = _sourceGeneratorExecutionVersionMap.Map.ToBuilder(); + var versionMapBuilder = SourceGeneratorExecutionVersionMap.Map.ToBuilder(); foreach (var projectId in projectIds) versionMapBuilder.Remove(projectId); @@ -488,18 +485,17 @@ public SolutionCompilationState WithProjectFilePath( /// public SolutionCompilationState WithProjectCompilationOptions( - ProjectId projectId, CompilationOptions options) + ProjectId projectId, CompilationOptions? options) { return ForkProject( this.SolutionState.WithProjectCompilationOptions(projectId, options), - static stateChange => new TranslationAction.ProjectCompilationOptionsAction( - stateChange.OldProjectState, stateChange.NewProjectState, isAnalyzerConfigChange: false), + static stateChange => new TranslationAction.ProjectCompilationOptionsAction(stateChange.OldProjectState, stateChange.NewProjectState), forkTracker: true); } /// public SolutionCompilationState WithProjectParseOptions( - ProjectId projectId, ParseOptions options) + ProjectId projectId, ParseOptions? options) { var stateChange = this.SolutionState.WithProjectParseOptions(projectId, options); @@ -553,6 +549,101 @@ public SolutionCompilationState WithProjectDocumentsOrder( forkTracker: true); } + public SolutionCompilationState WithProjectAttributes(ProjectInfo.ProjectAttributes attributes) + { + var projectId = attributes.Id; + var oldProject = SolutionState.GetRequiredProjectState(projectId); + + if (oldProject.ProjectInfo.Attributes.Language != attributes.Language) + { + throw new NotSupportedException(WorkspacesResources.Changing_project_language_is_not_supported); + } + + if (oldProject.ProjectInfo.Attributes.IsSubmission != attributes.IsSubmission) + { + throw new NotSupportedException(WorkspacesResources.Changing_project_between_ordinary_and_interactive_submission_is_not_supported); + } + + return + WithProjectName(projectId, attributes.Name) + .WithProjectAssemblyName(projectId, attributes.AssemblyName) + .WithProjectFilePath(projectId, attributes.FilePath) + .WithProjectOutputFilePath(projectId, attributes.OutputFilePath) + .WithProjectOutputRefFilePath(projectId, attributes.OutputRefFilePath) + .WithProjectCompilationOutputInfo(projectId, attributes.CompilationOutputInfo) + .WithProjectDefaultNamespace(projectId, attributes.DefaultNamespace) + .WithHasAllInformation(projectId, attributes.HasAllInformation) + .WithRunAnalyzers(projectId, attributes.RunAnalyzers) + .WithProjectChecksumAlgorithm(projectId, attributes.ChecksumAlgorithm); + } + + public SolutionCompilationState WithProjectInfo(ProjectInfo info) + { + var projectId = info.Id; + var newState = WithProjectAttributes(info.Attributes) + .WithProjectCompilationOptions(projectId, info.CompilationOptions) + .WithProjectParseOptions(projectId, info.ParseOptions) + .WithProjectReferences(projectId, info.ProjectReferences) + .WithProjectMetadataReferences(projectId, info.MetadataReferences) + .WithProjectAnalyzerReferences(projectId, info.AnalyzerReferences); + + var oldProjectState = SolutionState.GetRequiredProjectState(projectId); + + // Note: buffers are reused across all calls to UpdateDocuments and cleared after each: + using var _1 = ArrayBuilder.GetInstance(out var addedDocumentInfos); + using var _2 = ArrayBuilder.GetInstance(out var removedDocumentInfos); + + UpdateDocuments(info.Documents); + UpdateDocuments(info.AdditionalDocuments); + UpdateDocuments(info.AnalyzerConfigDocuments); + + return newState; + + void UpdateDocuments(IReadOnlyList newDocumentInfos) + where TDocumentState : TextDocumentState + { + Debug.Assert(addedDocumentInfos.IsEmpty); + Debug.Assert(removedDocumentInfos.IsEmpty); + + using var _3 = ArrayBuilder.GetInstance(out var updatedDocuments); + + var oldDocumentStates = oldProjectState.GetDocumentStates(); + + foreach (var newDocumentInfo in newDocumentInfos) + { + if (oldDocumentStates.TryGetState(newDocumentInfo.Id, out var oldDocumentState)) + { + var newDocumentState = (TDocumentState)oldDocumentState.WithDocumentInfo(newDocumentInfo); + if (oldDocumentState != newDocumentState) + { + updatedDocuments.Add(newDocumentState); + } + } + else + { + addedDocumentInfos.Add(newDocumentInfo); + } + } + + if (!oldDocumentStates.Ids.IsEmpty()) + { + var newDocumentIdSet = newDocumentInfos.Select(static d => d.Id).ToSet(); + foreach (var oldDocumentId in oldDocumentStates.Ids) + { + if (!newDocumentIdSet.Contains(oldDocumentId)) + { + removedDocumentInfos.Add(oldDocumentId); + } + } + } + + newState = newState + .WithDocumentStatesOfMultipleProjects([(projectId, updatedDocuments.ToImmutableAndClear())], GetUpdateDocumentsTranslationAction) + .AddDocumentsToMultipleProjects(addedDocumentInfos.ToImmutableAndClear()) + .RemoveDocumentsFromSingleProject(projectId, removedDocumentInfos.ToImmutableAndClear()); + } + } + /// public SolutionCompilationState AddProjectReferences( ProjectId projectId, IReadOnlyCollection projectReferences) @@ -688,70 +779,132 @@ public SolutionCompilationState WithProjectAnalyzerReferences( forkTracker: true); } - /// - public SolutionCompilationState WithDocumentName( - DocumentId documentId, string name) + /// + public SolutionCompilationState WithDocumentAttributes( + DocumentId documentId, + TArg arg, + Func updateAttributes) { return UpdateDocumentState( - this.SolutionState.WithDocumentName(documentId, name), documentId); + SolutionState.WithDocumentAttributes(documentId, arg, updateAttributes), documentId); } - /// - public SolutionCompilationState WithDocumentFolders( - DocumentId documentId, IReadOnlyList folders) + internal SolutionCompilationState WithDocumentTexts(ImmutableArray<(DocumentId documentId, SourceText text)> texts, PreservationMode mode) + => UpdateDocumentsInMultipleProjects( + texts, + arg: mode, + updateDocument: static (oldDocumentState, text, mode) => + SourceTextIsUnchanged(oldDocumentState, text) ? oldDocumentState : oldDocumentState.UpdateText(text, mode)); + + private static bool SourceTextIsUnchanged(DocumentState oldDocument, SourceText text) + => oldDocument.TryGetText(out var oldText) && text == oldText; + + /// + /// Applies an update operation to specified . + /// Documents may be in different projects. + /// + private SolutionCompilationState UpdateDocumentsInMultipleProjects( + ImmutableArray<(DocumentId documentId, TDocumentData documentData)> documentsToUpdate, + TArg arg, + Func updateDocument) + where TDocumentState : TextDocumentState { - return UpdateDocumentState( - this.SolutionState.WithDocumentFolders(documentId, folders), documentId); + return WithDocumentStatesOfMultipleProjects( + documentsToUpdate + .GroupBy(static d => d.documentId.ProjectId) + .Select(g => + { + var projectId = g.Key; + var oldProjectState = SolutionState.GetRequiredProjectState(projectId); + var oldDocumentStates = oldProjectState.GetDocumentStates(); + + using var _ = ArrayBuilder.GetInstance(out var newDocumentStates); + foreach (var (documentId, documentData) in g) + { + var oldDocumentState = oldDocumentStates.GetRequiredState(documentId); + var newDocumentState = updateDocument(oldDocumentState, documentData, arg); + + if (ReferenceEquals(oldDocumentState, newDocumentState)) + continue; + + newDocumentStates.Add(newDocumentState); + } + + return (projectId, newDocumentStates.ToImmutableAndClear()); + }), + GetUpdateDocumentsTranslationAction); } - /// - public SolutionCompilationState WithDocumentFilePath( - DocumentId documentId, string? filePath) + /// + /// Returns with projects updated to new document states specified in . + /// + private SolutionCompilationState WithDocumentStatesOfMultipleProjects( + IEnumerable<(ProjectId projectId, ImmutableArray updatedDocumentState)> updatedDocumentStatesPerProject, + Func, TranslationAction> getTranslationAction) + where TDocumentState : TextDocumentState { - return UpdateDocumentState( - this.SolutionState.WithDocumentFilePath(documentId, filePath), documentId); + var newCompilationState = this; + + foreach (var (projectId, newDocumentStates) in updatedDocumentStatesPerProject) + { + if (newDocumentStates.IsEmpty) + { + continue; + } + + var oldProjectState = newCompilationState.SolutionState.GetRequiredProjectState(projectId); + var compilationTranslationAction = getTranslationAction(oldProjectState, newDocumentStates); + var newProjectState = compilationTranslationAction.NewProjectState; + + var stateChange = newCompilationState.SolutionState.ForkProject( + oldProjectState, + newProjectState); + + newCompilationState = newCompilationState.ForkProject( + stateChange, + static (_, compilationTranslationAction) => compilationTranslationAction, + forkTracker: true, + arg: compilationTranslationAction); + } + + return newCompilationState; } - internal SolutionCompilationState WithDocumentTexts(ImmutableArray<(DocumentId documentId, SourceText text)> texts, PreservationMode mode) - => WithDocumentContents( - texts, SourceTextIsUnchanged, - static (documentState, text, mode) => documentState.UpdateText(text, mode), - data: mode); + /// + /// Updates the to a new state with and returns a that + /// reflects these changes in the project compilation. + /// + private static TranslationAction GetUpdateDocumentsTranslationAction(ProjectState oldProjectState, ImmutableArray newDocumentStates) + where TDocumentState : TextDocumentState + { + return newDocumentStates switch + { + ImmutableArray ordinaryNewDocumentStates => GetUpdateOrdinaryDocumentsTranslationAction(oldProjectState, ordinaryNewDocumentStates), + ImmutableArray additionalNewDocumentStates => GetUpdateAdditionalDocumentsTranslationAction(oldProjectState, additionalNewDocumentStates), + ImmutableArray analyzerConfigNewDocumentStates => GetUpdateAnalyzerConfigDocumentsTranslationAction(oldProjectState, analyzerConfigNewDocumentStates), + _ => throw ExceptionUtilities.UnexpectedValue(typeof(TDocumentState)) + }; - private static bool SourceTextIsUnchanged(DocumentState oldDocument, SourceText text, PreservationMode mode) - => oldDocument.TryGetText(out var oldText) && text == oldText; + TranslationAction GetUpdateOrdinaryDocumentsTranslationAction(ProjectState oldProjectState, ImmutableArray newDocumentStates) + { + var oldDocumentStates = newDocumentStates.SelectAsArray(static (s, oldProjectState) => oldProjectState.DocumentStates.GetRequiredState(s.Id), oldProjectState); + var newProjectState = oldProjectState.UpdateDocuments(oldDocumentStates, newDocumentStates); + return new TranslationAction.TouchDocumentsAction(oldProjectState, newProjectState, oldDocumentStates, newDocumentStates); + } - private SolutionCompilationState WithDocumentContents( - ImmutableArray<(DocumentId documentId, TContent content)> texts, - Func isUnchanged, - Func updateContent, - TData data) - { - return UpdateDocumentsInMultipleProjects( - texts.GroupBy(d => d.documentId.ProjectId).Select(g => - { - var projectId = g.Key; - var projectState = this.SolutionState.GetRequiredProjectState(projectId); - - using var _ = ArrayBuilder.GetInstance(out var newDocumentStates); - foreach (var (documentId, content) in g) - { - var documentState = projectState.DocumentStates.GetRequiredState(documentId); - if (isUnchanged(documentState, content, data)) - continue; - - newDocumentStates.Add(updateContent(documentState, content, data)); - } - - return (projectId, newDocumentStates.ToImmutableAndClear()); - }), - static (projectState, newDocumentStates) => - { - return new TranslationAction.TouchDocumentsAction( - projectState, - projectState.UpdateDocuments(newDocumentStates, contentChanged: true), - newDocumentStates); - }); + TranslationAction GetUpdateAdditionalDocumentsTranslationAction(ProjectState oldProjectState, ImmutableArray newDocumentStates) + { + var oldDocumentStates = newDocumentStates.SelectAsArray(static (s, oldProjectState) => oldProjectState.AdditionalDocumentStates.GetRequiredState(s.Id), oldProjectState); + var newProjectState = oldProjectState.UpdateAdditionalDocuments(oldDocumentStates, newDocumentStates); + return new TranslationAction.TouchAdditionalDocumentsAction(oldProjectState, newProjectState, oldDocumentStates, newDocumentStates); + } + + TranslationAction GetUpdateAnalyzerConfigDocumentsTranslationAction(ProjectState oldProjectState, ImmutableArray newDocumentStates) + { + var oldDocumentStates = newDocumentStates.SelectAsArray(static (s, oldProjectState) => oldProjectState.AnalyzerConfigDocumentStates.GetRequiredState(s.Id), oldProjectState); + var newProjectState = oldProjectState.UpdateAnalyzerConfigDocuments(oldDocumentStates, newDocumentStates); + return new TranslationAction.TouchAnalyzerConfigDocumentsAction(oldProjectState, newProjectState); + } } public SolutionCompilationState WithDocumentState( @@ -807,32 +960,25 @@ public SolutionCompilationState WithAnalyzerConfigDocumentText( /// public SolutionCompilationState WithDocumentSyntaxRoots(ImmutableArray<(DocumentId documentId, SyntaxNode root)> syntaxRoots, PreservationMode mode) { - return WithDocumentContents( - syntaxRoots, IsUnchanged, - static (documentState, root, mode) => documentState.UpdateTree(root, mode), - data: mode); - - static bool IsUnchanged(DocumentState oldDocument, SyntaxNode root, PreservationMode _) - { - return oldDocument.TryGetSyntaxTree(out var oldTree) && - oldTree.TryGetRoot(out var oldRoot) && - oldRoot == root; - } + return UpdateDocumentsInMultipleProjects( + syntaxRoots, + arg: mode, + static (oldDocumentState, root, mode) => + oldDocumentState.TryGetSyntaxTree(out var oldTree) && oldTree.TryGetRoot(out var oldRoot) && oldRoot == root + ? oldDocumentState + : oldDocumentState.UpdateTree(root, mode)); } public SolutionCompilationState WithDocumentContentsFrom( ImmutableArray<(DocumentId documentId, DocumentState documentState)> documentIdsAndStates, bool forceEvenIfTreesWouldDiffer) { - return WithDocumentContents( + return UpdateDocumentsInMultipleProjects( documentIdsAndStates, - isUnchanged: static (oldDocumentState, documentState, forceEvenIfTreesWouldDiffer) => - { - return oldDocumentState.TextAndVersionSource == documentState.TextAndVersionSource - && oldDocumentState.TreeSource == documentState.TreeSource; - }, + arg: forceEvenIfTreesWouldDiffer, static (oldDocumentState, documentState, forceEvenIfTreesWouldDiffer) => - oldDocumentState.UpdateTextAndTreeContents(documentState.TextAndVersionSource, documentState.TreeSource, forceEvenIfTreesWouldDiffer), - data: forceEvenIfTreesWouldDiffer); + oldDocumentState.TextAndVersionSource == documentState.TextAndVersionSource && oldDocumentState.TreeSource == documentState.TreeSource + ? oldDocumentState + : oldDocumentState.UpdateTextAndTreeContents(documentState.TextAndVersionSource, documentState.TreeSource, forceEvenIfTreesWouldDiffer)); } /// @@ -897,10 +1043,11 @@ private SolutionCompilationState UpdateDocumentState(StateChange stateChange, Do // This function shouldn't have been called if the document has not changed Debug.Assert(stateChange.OldProjectState != stateChange.NewProjectState); + var oldDocument = stateChange.OldProjectState.DocumentStates.GetRequiredState(documentId); var newDocument = stateChange.NewProjectState.DocumentStates.GetRequiredState(documentId); return new TranslationAction.TouchDocumentsAction( - stateChange.OldProjectState, stateChange.NewProjectState, [newDocument]); + stateChange.OldProjectState, stateChange.NewProjectState, [oldDocument], [newDocument]); }, forkTracker: true, arg: documentId); @@ -918,7 +1065,8 @@ private SolutionCompilationState UpdateAdditionalDocumentState(StateChange state var oldDocument = stateChange.OldProjectState.AdditionalDocumentStates.GetRequiredState(documentId); var newDocument = stateChange.NewProjectState.AdditionalDocumentStates.GetRequiredState(documentId); - return new TranslationAction.TouchAdditionalDocumentAction(stateChange.OldProjectState, stateChange.NewProjectState, oldDocument, newDocument); + return new TranslationAction.TouchAdditionalDocumentsAction( + stateChange.OldProjectState, stateChange.NewProjectState, [oldDocument], [newDocument]); }, forkTracker: true, arg: documentId); @@ -928,10 +1076,7 @@ private SolutionCompilationState UpdateAnalyzerConfigDocumentState(StateChange s { return ForkProject( stateChange, - static stateChange => stateChange.NewProjectState.CompilationOptions != null - ? new TranslationAction.ProjectCompilationOptionsAction( - stateChange.OldProjectState, stateChange.NewProjectState, isAnalyzerConfigChange: true) - : null, + static stateChange => new TranslationAction.TouchAnalyzerConfigDocumentsAction(stateChange.OldProjectState, stateChange.NewProjectState), forkTracker: true); } @@ -1269,7 +1414,7 @@ public SolutionCompilationState WithOptions(SolutionOptionSet options) } /// - /// Updates entries in our to the corresponding values in the + /// Updates entries in our to the corresponding values in the /// given . Importantly, must refer to projects in this solution. Projects not mentioned in /// will not be touched (and they will stay in the map). @@ -1277,7 +1422,7 @@ public SolutionCompilationState WithOptions(SolutionOptionSet options) public SolutionCompilationState UpdateSpecificSourceGeneratorExecutionVersions( SourceGeneratorExecutionVersionMap sourceGeneratorExecutionVersions) { - var versionMapBuilder = _sourceGeneratorExecutionVersionMap.Map.ToBuilder(); + var versionMapBuilder = SourceGeneratorExecutionVersionMap.Map.ToBuilder(); var newIdToTrackerMapBuilder = _projectIdToTrackerMap.ToBuilder(); var changed = false; @@ -1336,7 +1481,7 @@ private SolutionCompilationState ComputeFrozenSnapshot(CancellationToken cancell // Since we're freezing, set both generators and skeletons to not be created. We don't want to take any // perf hit on either of those at all for our clients. - var newTracker = oldTracker.WithDoNotCreateCreationPolicy(cancellationToken); + var newTracker = oldTracker.WithDoNotCreateCreationPolicy(); if (oldTracker == newTracker) continue; @@ -1479,70 +1624,22 @@ static SolutionCompilationState ComputeFrozenPartialState( } // Now, add all missing documents per project. - currentState = currentState.UpdateDocumentsInMultipleProjects( + currentState = currentState.WithDocumentStatesOfMultipleProjects( // Do a SelectAsArray here to ensure that we realize the array once, and as such only call things like // ToImmutableAndFree once per ArrayBuilder. missingDocumentStates.SelectAsArray(kvp => (kvp.Key, kvp.Value.ToImmutableAndFree())), - static (oldProjectState, newDocumentStates) => - new TranslationAction.AddDocumentsAction(oldProjectState, oldProjectState.AddDocuments(newDocumentStates), newDocumentStates)); + GetAddDocumentsTranslationAction); return currentState; } } - public SolutionCompilationState AddDocuments(ImmutableArray documentInfos) - { - return AddDocumentsToMultipleProjects(documentInfos, - static (documentInfo, project) => project.CreateDocument(documentInfo, project.ParseOptions, new LoadTextOptions(project.ChecksumAlgorithm)), - static (oldProject, documents) => new TranslationAction.AddDocumentsAction(oldProject, oldProject.AddDocuments(documents), documents)); - } - - public SolutionCompilationState AddAdditionalDocuments(ImmutableArray documentInfos) - { - return AddDocumentsToMultipleProjects(documentInfos, - static (documentInfo, project) => new AdditionalDocumentState(project.LanguageServices.SolutionServices, documentInfo, new LoadTextOptions(project.ChecksumAlgorithm)), - static (oldProject, documents) => new TranslationAction.AddAdditionalDocumentsAction(oldProject, oldProject.AddAdditionalDocuments(documents), documents)); - } - - public SolutionCompilationState AddAnalyzerConfigDocuments(ImmutableArray documentInfos) - { - return AddDocumentsToMultipleProjects(documentInfos, - static (documentInfo, project) => new AnalyzerConfigDocumentState(project.LanguageServices.SolutionServices, documentInfo, new LoadTextOptions(project.ChecksumAlgorithm)), - static (oldProject, documents) => new TranslationAction.ProjectCompilationOptionsAction(oldProject, oldProject.AddAnalyzerConfigDocuments(documents), isAnalyzerConfigChange: true)); - } - - public SolutionCompilationState RemoveDocuments(ImmutableArray documentIds) - { - return RemoveDocumentsFromMultipleProjects(documentIds, - static (projectState, documentId) => projectState.DocumentStates.GetRequiredState(documentId), - static (oldProject, documentIds, documentStates) => new TranslationAction.RemoveDocumentsAction(oldProject, oldProject.RemoveDocuments(documentIds), documentStates)); - } - - public SolutionCompilationState RemoveAdditionalDocuments(ImmutableArray documentIds) - { - return RemoveDocumentsFromMultipleProjects(documentIds, - static (projectState, documentId) => projectState.AdditionalDocumentStates.GetRequiredState(documentId), - static (oldProject, documentIds, documentStates) => new TranslationAction.RemoveAdditionalDocumentsAction(oldProject, oldProject.RemoveAdditionalDocuments(documentIds), documentStates)); - } - - public SolutionCompilationState RemoveAnalyzerConfigDocuments(ImmutableArray documentIds) - { - return RemoveDocumentsFromMultipleProjects(documentIds, - static (projectState, documentId) => projectState.AnalyzerConfigDocumentStates.GetRequiredState(documentId), - static (oldProject, documentIds, _) => new TranslationAction.ProjectCompilationOptionsAction(oldProject, oldProject.RemoveAnalyzerConfigDocuments(documentIds), isAnalyzerConfigChange: true)); - } - /// /// Core helper that takes a set of s and does the application of the appropriate documents to each project. /// /// The set of documents to add. - /// Returns the new with the documents added, - /// and the needed as - /// well. - private SolutionCompilationState AddDocumentsToMultipleProjects( - ImmutableArray documentInfos, - Func createDocumentState, - Func, TranslationAction> addDocumentsToProjectState) + public SolutionCompilationState AddDocumentsToMultipleProjects( + ImmutableArray documentInfos) where TDocumentState : TextDocumentState { if (documentInfos.IsDefault) @@ -1553,48 +1650,18 @@ private SolutionCompilationState AddDocumentsToMultipleProjects( // The documents might be contributing to multiple different projects; split them by project and then we'll // process one project at a time. - return UpdateDocumentsInMultipleProjects( + return WithDocumentStatesOfMultipleProjects( documentInfos.GroupBy(d => d.Id.ProjectId).Select(g => { var projectId = g.Key; - this.SolutionState.CheckContainsProject(projectId); - var projectState = this.SolutionState.GetRequiredProjectState(projectId); - return (projectId, newDocumentStates: g.SelectAsArray(di => createDocumentState(di, projectState))); + SolutionState.CheckContainsProject(projectId); + var projectState = SolutionState.GetRequiredProjectState(projectId); + return (projectId, newDocumentStates: g.SelectAsArray(projectState.CreateDocument)); }), - addDocumentsToProjectState); - } - - private SolutionCompilationState UpdateDocumentsInMultipleProjects( - IEnumerable<(ProjectId projectId, ImmutableArray updatedDocumentState)> projectIdAndUpdatedDocuments, - Func, TranslationAction> getTranslationAction) - where TDocumentState : TextDocumentState - { - var newCompilationState = this; - - foreach (var (projectId, newDocumentStates) in projectIdAndUpdatedDocuments) - { - var oldProjectState = newCompilationState.SolutionState.GetRequiredProjectState(projectId); - var compilationTranslationAction = getTranslationAction(oldProjectState, newDocumentStates); - var newProjectState = compilationTranslationAction.NewProjectState; - - var stateChange = newCompilationState.SolutionState.ForkProject( - oldProjectState, - newProjectState); - - newCompilationState = newCompilationState.ForkProject( - stateChange, - static (_, compilationTranslationAction) => compilationTranslationAction, - forkTracker: true, - arg: compilationTranslationAction); - } - - return newCompilationState; + GetAddDocumentsTranslationAction); } - private SolutionCompilationState RemoveDocumentsFromMultipleProjects( - ImmutableArray documentIds, - Func getExistingTextDocumentState, - Func, ImmutableArray, TranslationAction> removeDocumentsFromProjectState) + public SolutionCompilationState RemoveDocumentsFromMultipleProjects(ImmutableArray documentIds) where T : TextDocumentState { if (documentIds.IsEmpty) @@ -1610,39 +1677,59 @@ private SolutionCompilationState RemoveDocumentsFromMultipleProjects( foreach (var documentIdsInProject in documentIdsByProjectId) { - var oldProjectState = this.SolutionState.GetProjectState(documentIdsInProject.Key); + newCompilationState = newCompilationState.RemoveDocumentsFromSingleProject(documentIdsInProject.Key, [.. documentIdsInProject]); + } - if (oldProjectState == null) - { - throw new InvalidOperationException(string.Format(WorkspacesResources._0_is_not_part_of_the_workspace, documentIdsInProject.Key)); - } + return newCompilationState; + } - using var _ = ArrayBuilder.GetInstance(out var removedDocumentStates); + private SolutionCompilationState RemoveDocumentsFromSingleProject(ProjectId projectId, ImmutableArray documentIds) + where T : TextDocumentState + { + using var _ = ArrayBuilder.GetInstance(out var removedDocumentStates); - foreach (var documentId in documentIdsInProject) - { - removedDocumentStates.Add(getExistingTextDocumentState(oldProjectState, documentId)); - } + var oldProjectState = SolutionState.GetRequiredProjectState(projectId); + var oldDocumentStates = oldProjectState.GetDocumentStates(); - var removedDocumentStatesForProject = removedDocumentStates.ToImmutable(); + foreach (var documentId in documentIds) + { + removedDocumentStates.Add(oldDocumentStates.GetRequiredState(documentId)); + } - var compilationTranslationAction = removeDocumentsFromProjectState(oldProjectState, [.. documentIdsInProject], removedDocumentStatesForProject); - var newProjectState = compilationTranslationAction.NewProjectState; + var removedDocumentStatesForProject = removedDocumentStates.ToImmutable(); - var stateChange = newCompilationState.SolutionState.ForkProject( - oldProjectState, - newProjectState); + var compilationTranslationAction = GetRemoveDocumentsTranslationAction(oldProjectState, documentIds, removedDocumentStatesForProject); + var newProjectState = compilationTranslationAction.NewProjectState; - newCompilationState = newCompilationState.ForkProject( - stateChange, - static (_, compilationTranslationAction) => compilationTranslationAction, - forkTracker: true, - arg: compilationTranslationAction); - } + var stateChange = SolutionState.ForkProject( + oldProjectState, + newProjectState); - return newCompilationState; + return ForkProject( + stateChange, + static (_, compilationTranslationAction) => compilationTranslationAction, + forkTracker: true, + arg: compilationTranslationAction); } + private static TranslationAction GetRemoveDocumentsTranslationAction(ProjectState oldProject, ImmutableArray documentIds, ImmutableArray states) + => states switch + { + ImmutableArray documentStates => new TranslationAction.RemoveDocumentsAction(oldProject, oldProject.RemoveDocuments(documentIds), documentStates), + ImmutableArray additionalDocumentStates => new TranslationAction.RemoveAdditionalDocumentsAction(oldProject, oldProject.RemoveAdditionalDocuments(documentIds), additionalDocumentStates), + ImmutableArray _ => new TranslationAction.TouchAnalyzerConfigDocumentsAction(oldProject, oldProject.RemoveAnalyzerConfigDocuments(documentIds)), + _ => throw ExceptionUtilities.UnexpectedValue(states) + }; + + private static TranslationAction GetAddDocumentsTranslationAction(ProjectState oldProject, ImmutableArray states) + => states switch + { + ImmutableArray documentStates => new TranslationAction.AddDocumentsAction(oldProject, oldProject.AddDocuments(documentStates), documentStates), + ImmutableArray additionalDocumentStates => new TranslationAction.AddAdditionalDocumentsAction(oldProject, oldProject.AddAdditionalDocuments(additionalDocumentStates), additionalDocumentStates), + ImmutableArray analyzerConfigDocumentStates => new TranslationAction.TouchAnalyzerConfigDocumentsAction(oldProject, oldProject.AddAnalyzerConfigDocuments(analyzerConfigDocumentStates)), + _ => throw ExceptionUtilities.UnexpectedValue(states) + }; + /// public SolutionCompilationState WithCachedSourceGeneratorState(ProjectId projectToUpdate, Project projectWithCachedGeneratorState) { @@ -1696,7 +1783,7 @@ public SolutionCompilationState WithDocumentText(IEnumerable docume // the same text (for example, when GetOpenDocumentInCurrentContextWithChanges) is called. // // The use of GetRequiredState mirrors what happens in WithDocumentTexts - if (!SourceTextIsUnchanged(documentState, text, mode)) + if (!SourceTextIsUnchanged(documentState, text)) changedDocuments.Add((documentId, text)); } } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs index cc386042c1c14..653edb237c4e6 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs @@ -53,8 +53,6 @@ internal sealed partial class SolutionState /// internal ImmutableDictionary ProjectCountByLanguage { get; } = ImmutableDictionary.Empty; - private readonly SolutionInfo.SolutionAttributes _solutionAttributes; - private readonly ImmutableDictionary _projectIdToProjectStateMap; private readonly ProjectDependencyGraph _dependencyGraph; // holds on data calculated based on the AnalyzerReferences list @@ -78,14 +76,14 @@ private SolutionState( { WorkspaceKind = workspaceKind; WorkspaceVersion = workspaceVersion; - _solutionAttributes = solutionAttributes; + SolutionAttributes = solutionAttributes; Services = services; ProjectIds = projectIds; Options = options; AnalyzerReferences = analyzerReferences; FallbackAnalyzerOptions = fallbackAnalyzerOptions; ProjectCountByLanguage = projectCountByLanguage; - _projectIdToProjectStateMap = idToProjectStateMap; + ProjectStates = idToProjectStateMap; _dependencyGraph = dependencyGraph; _lazyAnalyzers = lazyAnalyzers ?? CreateLazyHostDiagnosticAnalyzers(analyzerReferences); @@ -126,24 +124,24 @@ public SolutionState( public HostDiagnosticAnalyzers Analyzers => _lazyAnalyzers.Value; - public SolutionInfo.SolutionAttributes SolutionAttributes => _solutionAttributes; + public SolutionInfo.SolutionAttributes SolutionAttributes { get; } - public ImmutableDictionary ProjectStates => _projectIdToProjectStateMap; + public ImmutableDictionary ProjectStates { get; } /// /// The Id of the solution. Multiple solution instances may share the same Id. /// - public SolutionId Id => _solutionAttributes.Id; + public SolutionId Id => SolutionAttributes.Id; /// /// The path to the solution file or null if there is no solution file. /// - public string? FilePath => _solutionAttributes.FilePath; + public string? FilePath => SolutionAttributes.FilePath; /// /// The solution version. This equates to the solution file's version. /// - public VersionStamp Version => _solutionAttributes.Version; + public VersionStamp Version => SolutionAttributes.Version; /// /// A list of all the ids for all the projects contained by the solution. @@ -153,14 +151,14 @@ public SolutionState( private void CheckInvariants() { // Run these quick checks all the time. We need to know immediately if we violate these. - Contract.ThrowIfFalse(_projectIdToProjectStateMap.Count == ProjectIds.Count); - Contract.ThrowIfFalse(_projectIdToProjectStateMap.Count == _dependencyGraph.ProjectIds.Count); + Contract.ThrowIfFalse(ProjectStates.Count == ProjectIds.Count); + Contract.ThrowIfFalse(ProjectStates.Count == _dependencyGraph.ProjectIds.Count); // Only run this in debug builds; even the .SetEquals() call across all projects can be expensive when there's a lot of them. #if DEBUG // project ids must be the same: - Debug.Assert(_projectIdToProjectStateMap.Keys.SetEquals(ProjectIds)); - Debug.Assert(_projectIdToProjectStateMap.Keys.SetEquals(_dependencyGraph.ProjectIds)); + Debug.Assert(ProjectStates.Keys.SetEquals(ProjectIds)); + Debug.Assert(ProjectStates.Keys.SetEquals(_dependencyGraph.ProjectIds)); #endif } @@ -174,9 +172,9 @@ internal SolutionState Branch( ImmutableDictionary? idToProjectStateMap = null, ProjectDependencyGraph? dependencyGraph = null) { - solutionAttributes ??= _solutionAttributes; + solutionAttributes ??= SolutionAttributes; projectIds ??= ProjectIds; - idToProjectStateMap ??= _projectIdToProjectStateMap; + idToProjectStateMap ??= ProjectStates; options ??= Options; analyzerReferences ??= AnalyzerReferences; fallbackAnalyzerOptions ??= FallbackAnalyzerOptions; @@ -185,13 +183,13 @@ internal SolutionState Branch( var analyzerReferencesEqual = AnalyzerReferences.SequenceEqual(analyzerReferences); - if (solutionAttributes == _solutionAttributes && + if (solutionAttributes == SolutionAttributes && projectIds == ProjectIds && options == Options && analyzerReferencesEqual && fallbackAnalyzerOptions == FallbackAnalyzerOptions && projectCountByLanguage == ProjectCountByLanguage && - idToProjectStateMap == _projectIdToProjectStateMap && + idToProjectStateMap == ProjectStates && dependencyGraph == _dependencyGraph) { return this; @@ -235,13 +233,13 @@ public SolutionState WithNewWorkspace( workspaceKind, workspaceVersion, services, - _solutionAttributes, + SolutionAttributes, ProjectIds, Options, AnalyzerReferences, FallbackAnalyzerOptions, ProjectCountByLanguage, - _projectIdToProjectStateMap, + ProjectStates, _dependencyGraph, _lazyAnalyzers); } @@ -265,7 +263,7 @@ public VersionStamp GetLatestProjectVersion() /// True if the solution contains a project with the specified project ID. /// public bool ContainsProject([NotNullWhen(returnValue: true)] ProjectId? projectId) - => projectId != null && _projectIdToProjectStateMap.ContainsKey(projectId); + => projectId != null && ProjectStates.ContainsKey(projectId); /// /// True if the solution contains the document in one of its projects @@ -310,7 +308,7 @@ private AnalyzerConfigDocumentState GetRequiredAnalyzerConfigDocumentState(Docum => GetRequiredProjectState(documentId.ProjectId).AnalyzerConfigDocumentStates.GetRequiredState(documentId); public ProjectState? GetProjectState(ProjectId projectId) - => _projectIdToProjectStateMap.TryGetValue(projectId, out var state) ? state : null; + => ProjectStates.TryGetValue(projectId, out var state) ? state : null; public ProjectState GetRequiredProjectState(ProjectId projectId) { @@ -372,11 +370,11 @@ ProjectState CreateProjectState(ProjectInfo projectInfo) SolutionState AddProjects(ArrayBuilder projectStates) { // changed project list so, increment version. - var newSolutionAttributes = _solutionAttributes.With(version: Version.GetNewerVersion()); + var newSolutionAttributes = SolutionAttributes.With(version: Version.GetNewerVersion()); using var _1 = ArrayBuilder.GetInstance(ProjectIds.Count + projectStates.Count, out var newProjectIdsBuilder); using var _2 = PooledHashSet.GetInstance(out var addedProjectIds); - var newStateMapBuilder = _projectIdToProjectStateMap.ToBuilder(); + var newStateMapBuilder = ProjectStates.ToBuilder(); newProjectIdsBuilder.AddRange(ProjectIds); @@ -434,14 +432,14 @@ public SolutionState RemoveProjects(ArrayBuilder projectIds) CheckContainsProject(projectId); // changed project list so, increment version. - var newSolutionAttributes = _solutionAttributes.With(version: this.Version.GetNewerVersion()); + var newSolutionAttributes = SolutionAttributes.With(version: this.Version.GetNewerVersion()); using var _ = PooledHashSet.GetInstance(out var projectIdsSet); projectIdsSet.AddRange(projectIds); var newProjectIds = ProjectIds.Where(p => !projectIdsSet.Contains(p)).ToBoxedImmutableArray(); - var newStateMapBuilder = _projectIdToProjectStateMap.ToBuilder(); + var newStateMapBuilder = ProjectStates.ToBuilder(); foreach (var projectId in projectIds) newStateMapBuilder.Remove(projectId); var newStateMap = newStateMapBuilder.ToImmutable(); @@ -454,7 +452,7 @@ public SolutionState RemoveProjects(ArrayBuilder projectIds) var languageCountDeltas = new TemporaryArray<(string language, int count)>(); foreach (var projectId in projectIds) { - AddLanguageCountDelta(ref languageCountDeltas, _projectIdToProjectStateMap[projectId].Language, amount: -1); + AddLanguageCountDelta(ref languageCountDeltas, ProjectStates[projectId].Language, amount: -1); } return this.Branch( @@ -637,7 +635,7 @@ public StateChange WithProjectFilePath(ProjectId projectId, string? filePath) /// Create a new solution instance with the project specified updated to have /// the specified compilation options. /// - public StateChange WithProjectCompilationOptions(ProjectId projectId, CompilationOptions options) + public StateChange WithProjectCompilationOptions(ProjectId projectId, CompilationOptions? options) { var oldProject = GetRequiredProjectState(projectId); var newProject = oldProject.WithCompilationOptions(options); @@ -654,7 +652,7 @@ public StateChange WithProjectCompilationOptions(ProjectId projectId, Compilatio /// Create a new solution instance with the project specified updated to have /// the specified parse options. /// - public StateChange WithProjectParseOptions(ProjectId projectId, ParseOptions options) + public StateChange WithProjectParseOptions(ProjectId projectId, ParseOptions? options) { var oldProject = GetRequiredProjectState(projectId); var newProject = oldProject.WithParseOptions(options); @@ -745,7 +743,7 @@ public StateChange RemoveProjectReference(ProjectId projectId, ProjectReference ProjectDependencyGraph newDependencyGraph; if (newProject.ContainsReferenceToProject(projectReference.ProjectId) || - !_projectIdToProjectStateMap.ContainsKey(projectReference.ProjectId)) + !ProjectStates.ContainsKey(projectReference.ProjectId)) { // Two cases: // 1) The project contained multiple non-equivalent references to the project, @@ -924,7 +922,7 @@ public SolutionState WithFallbackAnalyzerOptions(ImmutableDictionary entry.Key, elementSelector: entry => { @@ -944,49 +942,23 @@ public SolutionState WithFallbackAnalyzerOptions(ImmutableDictionary - /// Creates a new solution instance with the document specified updated to have the specified name. + /// Creates a new solution instance with an attribute of the document updated, if its value has changed. /// - public StateChange WithDocumentName(DocumentId documentId, string name) + public StateChange WithDocumentAttributes( + DocumentId documentId, + TArg arg, + Func updateAttributes) { var oldDocument = GetRequiredDocumentState(documentId); - if (oldDocument.Attributes.Name == name) - { - var oldProject = GetRequiredProjectState(documentId.ProjectId); - return new(this, oldProject, oldProject); - } - - return UpdateDocumentState(oldDocument.UpdateName(name), contentChanged: false); - } - /// - /// Creates a new solution instance with the document specified updated to be contained in - /// the sequence of logical folders. - /// - public StateChange WithDocumentFolders(DocumentId documentId, IReadOnlyList folders) - { - var oldDocument = GetRequiredDocumentState(documentId); - if (oldDocument.Folders.SequenceEqual(folders)) - { - var oldProject = GetRequiredProjectState(documentId.ProjectId); - return new(this, oldProject, oldProject); - } - - return UpdateDocumentState(oldDocument.UpdateFolders(folders), contentChanged: false); - } - - /// - /// Creates a new solution instance with the document specified updated to have the specified file path. - /// - public StateChange WithDocumentFilePath(DocumentId documentId, string? filePath) - { - var oldDocument = GetRequiredDocumentState(documentId); - if (oldDocument.FilePath == filePath) + var newDocument = oldDocument.WithAttributes(updateAttributes(oldDocument.Attributes, arg)); + if (ReferenceEquals(oldDocument, newDocument)) { var oldProject = GetRequiredProjectState(documentId.ProjectId); return new(this, oldProject, oldProject); } - return UpdateDocumentState(oldDocument.UpdateFilePath(filePath), contentChanged: false); + return UpdateDocumentState(newDocument); } /// @@ -1002,7 +974,7 @@ public StateChange WithDocumentText(DocumentId documentId, SourceText text, Pres return new(this, oldProject, oldProject); } - return UpdateDocumentState(oldDocument.UpdateText(text, mode), contentChanged: true); + return UpdateDocumentState(oldDocument.UpdateText(text, mode)); } public StateChange WithDocumentState(DocumentState newDocument) @@ -1014,7 +986,7 @@ public StateChange WithDocumentState(DocumentState newDocument) return new(this, oldProject, oldProject); } - return UpdateDocumentState(newDocument, contentChanged: true); + return UpdateDocumentState(newDocument); } /// @@ -1030,7 +1002,7 @@ public StateChange WithAdditionalDocumentText(DocumentId documentId, SourceText return new(this, oldProject, oldProject); } - return UpdateAdditionalDocumentState(oldDocument.UpdateText(text, mode), contentChanged: true); + return UpdateAdditionalDocumentState(oldDocument.UpdateText(text, mode)); } /// @@ -1062,7 +1034,7 @@ public StateChange WithDocumentText(DocumentId documentId, TextAndVersion textAn return new(this, oldProject, oldProject); } - return UpdateDocumentState(oldDocument.UpdateText(textAndVersion, mode), contentChanged: true); + return UpdateDocumentState(oldDocument.UpdateText(textAndVersion, mode)); } /// @@ -1078,7 +1050,7 @@ public StateChange WithAdditionalDocumentText(DocumentId documentId, TextAndVers return new(this, oldProject, oldProject); } - return UpdateAdditionalDocumentState(oldDocument.UpdateText(textAndVersion, mode), contentChanged: true); + return UpdateAdditionalDocumentState(oldDocument.UpdateText(textAndVersion, mode)); } /// @@ -1110,7 +1082,7 @@ public StateChange WithDocumentSourceCodeKind(DocumentId documentId, SourceCodeK return new(this, oldProject, oldProject); } - return UpdateDocumentState(oldDocument.UpdateSourceCodeKind(sourceCodeKind), contentChanged: true); + return UpdateDocumentState(oldDocument.UpdateSourceCodeKind(sourceCodeKind)); } public StateChange UpdateDocumentTextLoader(DocumentId documentId, TextLoader loader, PreservationMode mode) @@ -1119,7 +1091,7 @@ public StateChange UpdateDocumentTextLoader(DocumentId documentId, TextLoader lo // Assumes that content has changed. User could have closed a doc without saving and we are loading text // from closed file with old content. - return UpdateDocumentState(oldDocument.UpdateText(loader, mode), contentChanged: true); + return UpdateDocumentState(oldDocument.UpdateText(loader, mode)); } /// @@ -1132,7 +1104,7 @@ public StateChange UpdateAdditionalDocumentTextLoader(DocumentId documentId, Tex // Assumes that content has changed. User could have closed a doc without saving and we are loading text // from closed file with old content. - return UpdateAdditionalDocumentState(oldDocument.UpdateText(loader, mode), contentChanged: true); + return UpdateAdditionalDocumentState(oldDocument.UpdateText(loader, mode)); } /// @@ -1148,10 +1120,10 @@ public StateChange UpdateAnalyzerConfigDocumentTextLoader(DocumentId documentId, return UpdateAnalyzerConfigDocumentState(oldDocument.UpdateText(loader, mode)); } - private StateChange UpdateDocumentState(DocumentState newDocument, bool contentChanged) + private StateChange UpdateDocumentState(DocumentState newDocument) { - var oldProject = GetProjectState(newDocument.Id.ProjectId)!; - var newProject = oldProject.UpdateDocument(newDocument, contentChanged); + var oldProject = GetRequiredProjectState(newDocument.Id.ProjectId); + var newProject = oldProject.UpdateDocument(newDocument); // This method shouldn't have been called if the document has not changed. Debug.Assert(oldProject != newProject); @@ -1161,10 +1133,10 @@ private StateChange UpdateDocumentState(DocumentState newDocument, bool contentC newProject); } - private StateChange UpdateAdditionalDocumentState(AdditionalDocumentState newDocument, bool contentChanged) + private StateChange UpdateAdditionalDocumentState(AdditionalDocumentState newDocument) { - var oldProject = GetProjectState(newDocument.Id.ProjectId)!; - var newProject = oldProject.UpdateAdditionalDocument(newDocument, contentChanged); + var oldProject = GetRequiredProjectState(newDocument.Id.ProjectId); + var newProject = oldProject.UpdateAdditionalDocument(newDocument); // This method shouldn't have been called if the document has not changed. Debug.Assert(oldProject != newProject); @@ -1174,7 +1146,7 @@ private StateChange UpdateAdditionalDocumentState(AdditionalDocumentState newDoc private StateChange UpdateAnalyzerConfigDocumentState(AnalyzerConfigDocumentState newDocument) { - var oldProject = GetProjectState(newDocument.Id.ProjectId)!; + var oldProject = GetRequiredProjectState(newDocument.Id.ProjectId); var newProject = oldProject.UpdateAnalyzerConfigDocument(newDocument); // This method shouldn't have been called if the document has not changed. @@ -1196,8 +1168,8 @@ public StateChange ForkProject( { var projectId = newProjectState.Id; - Contract.ThrowIfFalse(_projectIdToProjectStateMap.ContainsKey(projectId)); - var newStateMap = _projectIdToProjectStateMap.SetItem(projectId, newProjectState); + Contract.ThrowIfFalse(ProjectStates.ContainsKey(projectId)); + var newStateMap = ProjectStates.SetItem(projectId, newProjectState); newDependencyGraph ??= _dependencyGraph; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs index 47b17c9ed6d8a..05ca3cc369275 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs @@ -3,9 +3,11 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.Contracts; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.SourceGeneration; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; @@ -107,7 +109,7 @@ private SourceGeneratedDocumentState( ITreeAndVersionSource treeSource, Lazy lazyContentHash, DateTime generationDateTime) - : base(languageServices, documentServiceProvider, attributes, options, textSource, loadTextOptions, treeSource) + : base(languageServices, documentServiceProvider, attributes, textSource, loadTextOptions, options, treeSource) { Identity = documentIdentity; @@ -125,6 +127,12 @@ private static Checksum ComputeContentHash(SourceText text) public SourceGeneratedDocumentContentIdentity GetContentIdentity() => new(this.GetOriginalSourceTextContentHash(), this.SourceText.Encoding?.WebName, this.SourceText.ChecksumAlgorithm); + protected override TextDocumentState UpdateAttributes(DocumentInfo.DocumentAttributes newAttributes) + => throw new NotSupportedException(WorkspacesResources.The_contents_of_a_SourceGeneratedDocument_may_not_be_changed); + + protected override TextDocumentState UpdateDocumentServiceProvider(IDocumentServiceProvider? newProvider) + => throw new NotSupportedException(WorkspacesResources.The_contents_of_a_SourceGeneratedDocument_may_not_be_changed); + protected override TextDocumentState UpdateText(ITextAndVersionSource newTextSource, PreservationMode mode, bool incremental) => throw new NotSupportedException(WorkspacesResources.The_contents_of_a_SourceGeneratedDocument_may_not_be_changed); @@ -172,7 +180,7 @@ public SourceGeneratedDocumentState WithGenerationDateTime(DateTime generationDa return new( this.Identity, this.LanguageServices, - this.Services, + this.DocumentServiceProvider, this.Attributes, this.ParseOptions, this.TextAndVersionSource, diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorIdentity.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorIdentity.cs index cf815501c688a..90115c90fed6c 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorIdentity.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratorIdentity.cs @@ -3,8 +3,11 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Immutable; using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; @@ -33,6 +36,13 @@ public static SourceGeneratorIdentity Create(ISourceGenerator generator, Analyze assemblyName.Name!, analyzerReference.FullPath, assemblyName.Version!, generatorType.FullName!); } - public static string GetGeneratorTypeName(ISourceGenerator generator) - => generator.GetGeneratorType().FullName!; + public static ImmutableArray GetIdentities( + AnalyzerReference analyzerReference, string language) + { + using var _ = ArrayBuilder.GetInstance(out var result); + foreach (var generator in analyzerReference.GetGenerators(language)) + result.Add(Create(generator, analyzerReference)); + + return result.ToImmutableAndClear(); + } } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs index 125116d8ac0c6..d746eb8576229 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocument.cs @@ -56,7 +56,7 @@ internal TextDocument(Project project, TextDocumentState state, TextDocumentKind /// /// A associated with this document /// - internal IDocumentServiceProvider Services => State.Services; + internal IDocumentServiceProvider DocumentServiceProvider => State.DocumentServiceProvider; /// /// Get the current text for the document if it is already loaded and available. diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs index bcf207ad2c851..dc92003f45237 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState.cs @@ -13,23 +13,17 @@ namespace Microsoft.CodeAnalysis; -internal partial class TextDocumentState +internal abstract partial class TextDocumentState { - protected readonly SolutionServices solutionServices; - - internal ITextAndVersionSource TextAndVersionSource { get; } + public readonly SolutionServices SolutionServices; + public readonly IDocumentServiceProvider DocumentServiceProvider; + public readonly DocumentInfo.DocumentAttributes Attributes; + public readonly ITextAndVersionSource TextAndVersionSource; public readonly LoadTextOptions LoadTextOptions; // Checksums for this solution state private readonly AsyncLazy _lazyChecksums; - public DocumentInfo.DocumentAttributes Attributes { get; } - - /// - /// A associated with this document - /// - public IDocumentServiceProvider Services { get; } - protected TextDocumentState( SolutionServices solutionServices, IDocumentServiceProvider? documentServiceProvider, @@ -37,13 +31,11 @@ protected TextDocumentState( ITextAndVersionSource textAndVersionSource, LoadTextOptions loadTextOptions) { - this.solutionServices = solutionServices; - - this.LoadTextOptions = loadTextOptions; - TextAndVersionSource = textAndVersionSource; - + SolutionServices = solutionServices; + DocumentServiceProvider = documentServiceProvider ?? DefaultTextDocumentServiceProvider.Instance; Attributes = attributes; - Services = documentServiceProvider ?? DefaultTextDocumentServiceProvider.Instance; + TextAndVersionSource = textAndVersionSource; + LoadTextOptions = loadTextOptions; // This constructor is called whenever we're creating a new TextDocumentState from another // TextDocumentState, and so we populate all the fields from the inputs. We will always create @@ -53,22 +45,29 @@ protected TextDocumentState( _lazyChecksums = AsyncLazy.Create(static (self, cancellationToken) => self.ComputeChecksumsAsync(cancellationToken), arg: this); } - public TextDocumentState(SolutionServices solutionServices, DocumentInfo info, LoadTextOptions loadTextOptions) - : this(solutionServices, - info.DocumentServiceProvider, - info.Attributes, - textAndVersionSource: info.TextLoader != null - ? CreateTextFromLoader(info.TextLoader, PreservationMode.PreserveValue, solutionServices) - : CreateStrongText(TextAndVersion.Create(SourceText.From(string.Empty, encoding: null, loadTextOptions.ChecksumAlgorithm), VersionStamp.Default, info.FilePath)), - loadTextOptions) - { - } - public DocumentId Id => Attributes.Id; public string? FilePath => Attributes.FilePath; public IReadOnlyList Folders => Attributes.Folders; public string Name => Attributes.Name; + public TextDocumentState WithDocumentInfo(DocumentInfo info) + => WithAttributes(info.Attributes) + .WithDocumentServiceProvider(info.DocumentServiceProvider) + .WithTextLoader(info.TextLoader, PreservationMode.PreserveValue); + + public TextDocumentState WithAttributes(DocumentInfo.DocumentAttributes newAttributes) + => ReferenceEquals(newAttributes, Attributes) ? this : UpdateAttributes(newAttributes); + + public TextDocumentState WithDocumentServiceProvider(IDocumentServiceProvider? newProvider) + => ReferenceEquals(newProvider, DocumentServiceProvider) ? this : UpdateDocumentServiceProvider(newProvider); + + public TextDocumentState WithTextLoader(TextLoader? loader, PreservationMode mode) + => ReferenceEquals(loader, TextAndVersionSource.TextLoader) ? this : UpdateText(loader, mode); + + protected abstract TextDocumentState UpdateAttributes(DocumentInfo.DocumentAttributes newAttributes); + protected abstract TextDocumentState UpdateDocumentServiceProvider(IDocumentServiceProvider? newProvider); + protected abstract TextDocumentState UpdateText(ITextAndVersionSource newTextSource, PreservationMode mode, bool incremental); + private static ConstantTextAndVersionSource CreateStrongText(TextAndVersion text) => new(text); @@ -139,7 +138,7 @@ public async Task GetTextVersionAsync(CancellationToken cancellati public TextDocumentState UpdateText(TextAndVersion newTextAndVersion, PreservationMode mode) => UpdateText(mode == PreservationMode.PreserveIdentity ? CreateStrongText(newTextAndVersion) - : CreateRecoverableText(newTextAndVersion, solutionServices), + : CreateRecoverableText(newTextAndVersion, SolutionServices), mode, incremental: true); @@ -151,15 +150,20 @@ public TextDocumentState UpdateText(SourceText newText, PreservationMode mode) return UpdateText(newTextAndVersion, mode); } - public TextDocumentState UpdateText(TextLoader loader, PreservationMode mode) + public TextDocumentState UpdateText(TextLoader? loader, PreservationMode mode) { // don't blow up on non-text documents. - var newTextSource = CreateTextFromLoader(loader, mode, this.solutionServices); + var newTextSource = CreateTextAndVersionSource(SolutionServices, loader, FilePath, LoadTextOptions, mode); return UpdateText(newTextSource, mode, incremental: false); } - private static ITextAndVersionSource CreateTextFromLoader(TextLoader loader, PreservationMode mode, SolutionServices solutionServices) + protected static ITextAndVersionSource CreateTextAndVersionSource(SolutionServices solutionServices, TextLoader? loader, string? filePath, LoadTextOptions loadTextOptions, PreservationMode mode = PreservationMode.PreserveValue) + => loader != null + ? CreateTextFromLoader(solutionServices, loader, mode) + : CreateStrongText(TextAndVersion.Create(SourceText.From(string.Empty, encoding: null, loadTextOptions.ChecksumAlgorithm), VersionStamp.Default, filePath)); + + private static ITextAndVersionSource CreateTextFromLoader(SolutionServices solutionServices, TextLoader loader, PreservationMode mode) { // If the caller is explicitly stating that identity must be preserved, then we created a source that will load // from the loader the first time, but then cache that result so that hte same result is *always* returned. @@ -179,16 +183,6 @@ private static ITextAndVersionSource CreateTextFromLoader(TextLoader loader, Pre return new RecoverableTextAndVersion(new LoadableTextAndVersionSource(loader, cacheResult: false), solutionServices); } - protected virtual TextDocumentState UpdateText(ITextAndVersionSource newTextSource, PreservationMode mode, bool incremental) - { - return new TextDocumentState( - solutionServices, - this.Services, - this.Attributes, - textAndVersionSource: newTextSource, - LoadTextOptions); - } - private ValueTask GetTextAndVersionAsync(CancellationToken cancellationToken) { if (this.TextAndVersionSource.TryGetValue(LoadTextOptions, out var textAndVersion)) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState_Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState_Checksum.cs index 3f646f09e1971..6f80aabca17cc 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState_Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState_Checksum.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis; -internal partial class TextDocumentState +internal abstract partial class TextDocumentState { public bool TryGetStateChecksums([NotNullWhen(returnValue: true)] out DocumentStateChecksums? stateChecksums) => _lazyChecksums.TryGetValue(out stateChecksums); diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs index 12f497396a5e9..33ead1daf977d 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentStates.cs @@ -49,14 +49,6 @@ internal sealed class TextDocumentStates #endif private readonly ImmutableList _ids; - - /// - /// The entries in the map are sorted by , which yields locally deterministic order but not the order that - /// matches the order in which documents were added. Therefore this ordering can't be used when creating compilations and it can't be - /// used when persisting document lists that do not preserve the GUIDs. - /// - private readonly ImmutableSortedDictionary _map; - private FilePathToDocumentIds? _filePathToDocumentIds; private TextDocumentStates( @@ -67,7 +59,7 @@ private TextDocumentStates( Debug.Assert(map.KeyComparer == DocumentIdComparer.Instance); _ids = ids; - _map = map; + States = map; _filePathToDocumentIds = filePathToDocumentIds; } @@ -86,25 +78,25 @@ public TextDocumentStates(IEnumerable infos, Func WithCompilationOrder(ImmutableList ids) - => new(ids, _map, _filePathToDocumentIds); + => new(ids, States, _filePathToDocumentIds); public int Count - => _map.Count; + => States.Count; public bool IsEmpty => Count == 0; public bool Contains(DocumentId id) - => _map.ContainsKey(id); + => States.ContainsKey(id); public bool TryGetState(DocumentId documentId, [NotNullWhen(true)] out TState? state) - => _map.TryGetValue(documentId, out state); + => States.TryGetValue(documentId, out state); public TState? GetState(DocumentId documentId) - => _map.TryGetValue(documentId, out var state) ? state : null; + => States.TryGetValue(documentId, out var state) ? state : null; public TState GetRequiredState(DocumentId documentId) - => _map.TryGetValue(documentId, out var state) ? state : throw ExceptionUtilities.Unreachable(); + => States.TryGetValue(documentId, out var state) ? state : throw ExceptionUtilities.Unreachable(); /// /// s in the order in which they were added to the project (the compilation order). @@ -114,8 +106,12 @@ public TState GetRequiredState(DocumentId documentId) /// /// States ordered by . /// - public ImmutableSortedDictionary States - => _map; + /// + /// The entries in the map are sorted by , which yields locally deterministic order but not the order that + /// matches the order in which documents were added. Therefore this ordering can't be used when creating compilations and it can't be + /// used when persisting document lists that do not preserve the GUIDs. + /// + public ImmutableSortedDictionary States { get; } /// /// Get states ordered in compilation order. @@ -123,7 +119,7 @@ public ImmutableSortedDictionary States /// public IEnumerable GetStatesInCompilationOrder() { - var map = _map; + var map = States; return Ids.Select(id => map[id]); } @@ -134,8 +130,8 @@ public ImmutableArray SelectAsArray(Func selecto public ImmutableArray SelectAsArray(Func selector, TArg arg) { - var result = new FixedSizeArrayBuilder(_map.Count); - foreach (var (_, state) in _map) + var result = new FixedSizeArrayBuilder(States.Count); + foreach (var (_, state) in States) result.Add(selector(state, arg)); return result.MoveToImmutable(); @@ -143,7 +139,7 @@ public ImmutableArray SelectAsArray(Func AddRange(ImmutableArray states) => new(_ids.AddRange(states.Select(state => state.Id)), - _map.AddRange(states.Select(state => KeyValuePairUtil.Create(state.Id, state))), + States.AddRange(states.Select(state => KeyValuePairUtil.Create(state.Id, state))), filePathToDocumentIds: null); public TextDocumentStates RemoveRange(ImmutableArray ids) @@ -152,7 +148,7 @@ public TextDocumentStates RemoveRange(ImmutableArray ids) { using var _ = PooledHashSet.GetInstance(out var set); -#if NETCOREAPP +#if NET set.EnsureCapacity(ids.Length); #endif @@ -164,7 +160,7 @@ public TextDocumentStates RemoveRange(ImmutableArray ids) } IEnumerable enumerableIds = ids; - return new(_ids.RemoveRange(enumerableIds), _map.RemoveRange(enumerableIds), filePathToDocumentIds: null); + return new(_ids.RemoveRange(enumerableIds), States.RemoveRange(enumerableIds), filePathToDocumentIds: null); } internal TextDocumentStates SetState(TState state) @@ -172,13 +168,13 @@ internal TextDocumentStates SetState(TState state) internal TextDocumentStates SetStates(ImmutableArray states) { - var builder = _map.ToBuilder(); + var builder = States.ToBuilder(); var filePathToDocumentIds = _filePathToDocumentIds; foreach (var state in states) { var id = state.Id; - var oldState = _map[id]; + var oldState = States[id]; // If any file paths have changed, don't preseve the computed map. We'll regenerate the new map on demand when needed. if (filePathToDocumentIds != null && oldState.FilePath != state.FilePath) @@ -192,9 +188,9 @@ internal TextDocumentStates SetStates(ImmutableArray states) public TextDocumentStates UpdateStates(Func transformation, TArg arg) { - var builder = _map.ToBuilder(); + var builder = States.ToBuilder(); var filePathsChanged = false; - foreach (var (id, state) in _map) + foreach (var (id, state) in States) { var newState = transformation(state, arg); @@ -226,7 +222,7 @@ public IEnumerable GetChangedStateIds(TextDocumentStates old continue; } - var newState = _map[id]; + var newState = States[id]; if (newState == oldState) { continue; @@ -245,13 +241,13 @@ public IEnumerable GetChangedStateIds(TextDocumentStates old /// Returns a s of added documents. /// public IEnumerable GetAddedStateIds(TextDocumentStates oldStates) - => (_ids == oldStates._ids) ? [] : Except(_ids, oldStates._map); + => (_ids == oldStates._ids) ? [] : Except(_ids, oldStates.States); /// /// Returns a s of removed documents. /// public IEnumerable GetRemovedStateIds(TextDocumentStates oldStates) - => (_ids == oldStates._ids) ? [] : Except(oldStates._ids, _map); + => (_ids == oldStates._ids) ? [] : Except(oldStates._ids, States); private static IEnumerable Except(ImmutableList ids, ImmutableSortedDictionary map) { @@ -265,7 +261,7 @@ private static IEnumerable Except(ImmutableList ids, Imm } public bool HasAnyStateChanges(TextDocumentStates oldStates) - => !_map.Values.SequenceEqual(oldStates._map.Values); + => !States.Values.SequenceEqual(oldStates.States.Values); public override bool Equals(object? obj) => obj is TextDocumentStates other && Equals(other); @@ -274,7 +270,7 @@ public override int GetHashCode() => throw new NotSupportedException(); public bool Equals(TextDocumentStates other) - => _map == other._map && _ids == other.Ids; + => States == other.States && _ids == other.Ids; private sealed class DocumentIdComparer : IComparer { @@ -301,11 +297,11 @@ public int Compare(DocumentId? x, DocumentId? y) public async ValueTask GetDocumentChecksumsAndIdsAsync(CancellationToken cancellationToken) { - var attributeChecksums = new FixedSizeArrayBuilder(_map.Count); - var textChecksums = new FixedSizeArrayBuilder(_map.Count); - var documentIds = new FixedSizeArrayBuilder(_map.Count); + var attributeChecksums = new FixedSizeArrayBuilder(States.Count); + var textChecksums = new FixedSizeArrayBuilder(States.Count); + var documentIds = new FixedSizeArrayBuilder(States.Count); - foreach (var (documentId, state) in _map) + foreach (var (documentId, state) in States) { var stateChecksums = await state.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); attributeChecksums.Add(stateChecksums.Info); @@ -351,7 +347,7 @@ private FilePathToDocumentIds ComputeFilePathToDocumentIds() var result = new Dictionary>(SolutionState.FilePathComparer); #endif - foreach (var (documentId, state) in _map) + foreach (var (documentId, state) in States) { var filePath = state.FilePath; if (filePath is null) diff --git a/src/Workspaces/Core/Portable/Workspace/Workspace.cs b/src/Workspaces/Core/Portable/Workspace/Workspace.cs index 7f7e86d82952e..bf651d7826c62 100644 --- a/src/Workspaces/Core/Portable/Workspace/Workspace.cs +++ b/src/Workspaces/Core/Portable/Workspace/Workspace.cs @@ -17,9 +17,9 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -34,9 +34,6 @@ namespace Microsoft.CodeAnalysis; /// public abstract partial class Workspace : IDisposable { - private readonly string? _workspaceKind; - private readonly HostWorkspaceServices _services; - private readonly ILegacyGlobalOptionService _legacyOptions; // forces serialization of mutation calls from host (OnXXX methods). Must take this lock before taking stateLock. @@ -69,16 +66,16 @@ public abstract partial class Workspace : IDisposable /// A string that can be used to identify the kind of workspace. Usually this matches the name of the class. protected Workspace(HostServices host, string? workspaceKind) { - _workspaceKind = workspaceKind; + Kind = workspaceKind; - _services = host.CreateWorkspaceServices(this); + Services = host.CreateWorkspaceServices(this); - _legacyOptions = _services.GetRequiredService().LegacyGlobalOptions; + _legacyOptions = Services.GetRequiredService().LegacyGlobalOptions; _legacyOptions.RegisterWorkspace(this); // queue used for sending events - var schedulerProvider = _services.GetRequiredService(); - var listenerProvider = _services.GetRequiredService(); + var schedulerProvider = Services.GetRequiredService(); + var listenerProvider = Services.GetRequiredService(); _taskQueue = new TaskQueue(listenerProvider.GetListener(), schedulerProvider.CurrentContextScheduler); // initialize with empty solution @@ -100,7 +97,7 @@ protected Workspace(HostServices host, string? workspaceKind) /// /// Services provider by the host for implementing workspace features. /// - public HostWorkspaceServices Services => _services; + public HostWorkspaceServices Services { get; } /// /// Override this property if the workspace supports partial semantics for documents. @@ -113,7 +110,7 @@ protected Workspace(HostServices host, string? workspaceKind) /// any other name used for a specific kind of workspace. /// // TODO (https://github.com/dotnet/roslyn/issues/37110): decide if Kind should be non-null - public string? Kind => _workspaceKind; + public string? Kind { get; } /// /// Create a new empty solution instance associated with this workspace. @@ -692,13 +689,9 @@ protected virtual void Dispose(bool finalize) _legacyOptions.UnregisterWorkspace(this); - // Directly dispose IRemoteHostClientProvider if necessary. This is a test hook to ensure RemoteWorkspace - // gets disposed in unit tests as soon as TestWorkspace gets disposed. This would be superseded by direct - // support for IDisposable in https://github.com/dotnet/roslyn/pull/47951. - if (Services.GetService() is IDisposable disposableService) - { - disposableService.Dispose(); - } + // Dispose per-instance services created for this workspace (direct MEF exports, including factories, will + // be disposed when the MEF catalog is disposed). + Services.Dispose(); // We're disposing this workspace. Stop any work to update SG docs in the background. _updateSourceGeneratorsQueueTokenSource.Cancel(); @@ -1610,7 +1603,7 @@ private void ApplyDocumentsInfoChange(ImmutableArray projectChan { // ApplyDocumentInfoChanged ignores the loader information, so we can pass null for it ApplyDocumentInfoChanged(newDoc.Id, - new DocumentInfo(newDoc.DocumentState.Attributes, loader: null, documentServiceProvider: newDoc.State.Services)); + new DocumentInfo(newDoc.DocumentState.Attributes, loader: null, documentServiceProvider: newDoc.State.DocumentServiceProvider)); } } @@ -2025,7 +2018,7 @@ internal static DocumentInfo CreateDocumentInfoWithoutText(TextDocument doc) filePath: doc.FilePath, isGenerated: doc.State.Attributes.IsGenerated) .WithDesignTimeOnly(doc.State.Attributes.DesignTimeOnly) - .WithDocumentServiceProvider(doc.Services); + .WithDocumentServiceProvider(doc.DocumentServiceProvider); /// /// This method is called during to add a project to the current solution. diff --git a/src/Workspaces/Core/Portable/WorkspacesResources.resx b/src/Workspaces/Core/Portable/WorkspacesResources.resx index a709923a19396..9b87404617148 100644 --- a/src/Workspaces/Core/Portable/WorkspacesResources.resx +++ b/src/Workspaces/Core/Portable/WorkspacesResources.resx @@ -439,9 +439,6 @@ Adding imports will bring an extension method into scope with the same name as '{0}' - - Document does not support syntax trees - {0} is in a different project. @@ -498,4 +495,16 @@ Applying changes to {0} + + Removing compilation options is not supported + + + Removing parse options is not supported + + + Changing project language is not supported + + + Changing project between ordinary and interactive submission is not supported + \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf index 60e51a38b0cd8..4d94ad62481a3 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf @@ -42,6 +42,16 @@ Změna dokumentu {0} není podporovaná. + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution Příkaz CodeAction {0} nevytvořil změněné řešení. @@ -57,11 +67,6 @@ DateTimeKind musí být Utc - - Document does not support syntax trees - Dokument nepodporuje stromy syntaxe. - - Error reading content of source file '{0}' -- '{1}'. Při čtení obsahu zdrojového souboru {0} došlo k chybě -- {1} @@ -127,6 +132,16 @@ Odebírání dokumentů konfigurace analyzátoru se nepodporuje. + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' Přejmenovat {0} na {1} diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf index 8187f2a68ed21..68b764580e04c 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf @@ -42,6 +42,16 @@ Das Ändern des Dokuments "{0}" wird nicht unterstützt. + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution Durch CodeAction "{0}" wurde keine geänderte Lösung erstellt. @@ -57,11 +67,6 @@ "DateTimeKind" muss UTC sein. - - Document does not support syntax trees - Das Dokument unterstützt keine Syntaxstrukturen. - - Error reading content of source file '{0}' -- '{1}'. Fehler beim Lesen des Inhalts der Quelldatei "{0}": "{1}". @@ -127,6 +132,16 @@ Das Entfernen von Konfigurationsdokumenten des Analysetools wird nicht unterstützt. + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' "{0}" in "{1}" umbenennen diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf index dbc16668c3574..4c5dcbad6fcd2 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf @@ -42,6 +42,16 @@ Documento cambiante '{0}' no es compatible. + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution El tipo CodeAction "{0}" no generó una solución modificada @@ -57,11 +67,6 @@ DateTimeKind debe ser Utc - - Document does not support syntax trees - El documento no admite árboles de sintaxis - - Error reading content of source file '{0}' -- '{1}'. Error al leer el contenido del archivo de origen "{0}"--"{1}". @@ -127,6 +132,16 @@ No se permite quitar documentos de configuración del analizador. + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' Cambiar el nombre de '{0}' a '{1}' diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf index e4a81592000eb..7c11afadb30ef 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf @@ -42,6 +42,16 @@ Le changement du document '{0}' n'est pas pris en charge. + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution Le CodeAction '{0}' n'a pas produit de solution contenant des changements @@ -57,11 +67,6 @@ DateTimeKind doit être UTC - - Document does not support syntax trees - Le document ne prend pas en charge les arborescences de syntaxe - - Error reading content of source file '{0}' -- '{1}'. Erreur durant la lecture du contenu du fichier source '{0}' -- '{1}'. @@ -127,6 +132,16 @@ La suppression de documents de configuration de l'analyseur n'est pas prise en charge. + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' Renommer '{0}' en '{1}' diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf index 54988fbbc4331..b8c8dd6affac9 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf @@ -42,6 +42,16 @@ La modifica del documento '{0}' non è supportata. + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution L'elemento CodeAction '{0}' non ha generato una soluzione modificata @@ -57,11 +67,6 @@ Il valore di DateTimeKind deve essere Utc - - Document does not support syntax trees - Il documento non supporta alberi di sintassi - - Error reading content of source file '{0}' -- '{1}'. Si è verificato un errore durante la lettura del contenuto del file di origine '{0}' - '{1}'. @@ -127,6 +132,16 @@ La rimozione di documenti di configurazione dell'analizzatore non è supportata. + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' Rinomina '{0}' in '{1}' diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf index 8da74f6c104bc..ca7e8ad4c8d1f 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf @@ -42,6 +42,16 @@ ドキュメント '{0}' の変更はサポートされていません。 + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution CodeAction '{0}' は変更されたソリューションを生成しませんでした @@ -57,11 +67,6 @@ DateTimeKind は Utc にする必要があります - - Document does not support syntax trees - ドキュメントでは構文ツリーがサポートされません - - Error reading content of source file '{0}' -- '{1}'. ソース ファイル '{0}' のコンテンツの読み取りでエラーが発生しました -- '{1}'。 @@ -127,6 +132,16 @@ アナライザー構成ドキュメントの削除はサポートされていません。 + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' '{0}' を '{1}' に名前変更 diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf index 8ce2d1127bfac..eff49c6c7e81c 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf @@ -42,6 +42,16 @@ '{0}' 문서 변경은 지원되지 않습니다. + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution CodeAction '{0}'이(가) 변경된 솔루션을 생성하지 않았습니다. @@ -57,11 +67,6 @@ DateTimeKind는 UTC여야 합니다. - - Document does not support syntax trees - 문서가 구문 트리를 지원하지 않음 - - Error reading content of source file '{0}' -- '{1}'. 소스 파일 '{0}'의 콘텐츠를 읽는 동안 오류가 발생했습니다. -- '{1}'. @@ -127,6 +132,16 @@ 분석기 구성 문서 제거는 지원되지 않습니다. + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' '{1}'(으)로 '{0}' 이름 바꾸기 diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf index fbbcad5818a48..73c27e5a01c9c 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf @@ -42,6 +42,16 @@ Zmiana dokumentu „{0}” nie jest obsługiwana. + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution Element CodeAction „{0}” nie utworzył zmienionego rozwiązania @@ -57,11 +67,6 @@ Element DateTimeKind musi mieć wartość Utc - - Document does not support syntax trees - Dokument nie obsługuje drzew składni - - Error reading content of source file '{0}' -- '{1}'. Błąd podczas odczytywania zawartości pliku źródłowego „{0}”--„{1}”. @@ -127,6 +132,16 @@ Usuwanie dokumentów z konfiguracją analizatora nie jest obsługiwane. + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' Zmień nazwę elementu „{0}” na „{1}” diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf index f40532fc600e8..d4623791d56d1 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf @@ -42,6 +42,16 @@ Não há suporte para alterar o documento '{0}'. + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution A CodeAction '{0}' não produziu uma solução alterada @@ -57,11 +67,6 @@ DateTimeKind deve ser Utc - - Document does not support syntax trees - O documento não dá suporte a árvores de sintaxe - - Error reading content of source file '{0}' -- '{1}'. Erro ao ler o conteúdo do arquivo de origem '{0}' – '{1}'. @@ -127,6 +132,16 @@ Não há suporte para a remoção de documentos da configuração do analisador. + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' Renomear "{0}" para "{1}" diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf index 28125f3f1479e..98221de788cdd 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf @@ -42,6 +42,16 @@ Изменение документа "{0}" не поддерживается. + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution Действие кода "{0}" не сформировало измененное решение. @@ -57,11 +67,6 @@ Параметр DateTimeKind должен содержать время и дату в формате UTC - - Document does not support syntax trees - Документ не поддерживает синтаксические деревья. - - Error reading content of source file '{0}' -- '{1}'. Ошибка при чтении содержимого исходного файла "{0}" — "{1}". @@ -127,6 +132,16 @@ Удаление документов конфигурации анализатора не поддерживается. + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' Переименовать "{0}" в "{1}" diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf index 0ab8ac724cd29..f9df174cf9a32 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf @@ -42,6 +42,16 @@ Değişen belge '{0}' desteklenmiyor. + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution '{0}' CodeAction, değiştirilmiş çözüm üretmedi @@ -57,11 +67,6 @@ DateTimeKind Utc olmalıdır - - Document does not support syntax trees - Belge, söz dizimi ağaçlarını desteklemiyor - - Error reading content of source file '{0}' -- '{1}'. '{0}' kaynak dosyasının içeriği okunurken hata oluştu -- '{1}'. @@ -127,6 +132,16 @@ Çözümleyici yapılandırma belgelerinin kaldırılması desteklenmiyor. + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' '{0}' öğesini '{1}' olarak yeniden adlandır diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf index 16e12f7ed8041..f470b5cbca67b 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf @@ -42,6 +42,16 @@ 不支持更改文档“{0}”。 + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution CodeAction "{0}" 未生成更改的解决方案 @@ -57,11 +67,6 @@ DateTimeKind 必须是 Utc - - Document does not support syntax trees - 文档不支持语法树 - - Error reading content of source file '{0}' -- '{1}'. 读取源文件“{0}”中的内容时出错 -“{1}”。 @@ -127,6 +132,16 @@ 不支持删除分析器配置文档。 + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' 将“{0}” 重命名为“{1}” diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf index 85a4efb9ae248..6fe2a8e3634b5 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf @@ -42,6 +42,16 @@ 不支援變更文件 '{0}'。 + + Changing project between ordinary and interactive submission is not supported + Changing project between ordinary and interactive submission is not supported + + + + Changing project language is not supported + Changing project language is not supported + + CodeAction '{0}' did not produce a changed solution CodeAction '{0}' 未產生變更的解決方案 @@ -57,11 +67,6 @@ DateTimeKind 必須是 Utc - - Document does not support syntax trees - 文件不支援語法樹 - - Error reading content of source file '{0}' -- '{1}'. 讀取來源檔案 '{0}' 的內容時發生錯誤 -- '{1}'。 @@ -127,6 +132,16 @@ 不支援移除分析器組態文件。 + + Removing compilation options is not supported + Removing compilation options is not supported + + + + Removing parse options is not supported + Removing parse options is not supported + + Rename '{0}' to '{1}' 將 '{0}' 重新命名為 '{1}' diff --git a/src/Workspaces/CoreTest/ChecksumTests.cs b/src/Workspaces/CoreTest/ChecksumTests.cs index c7c67a0270245..d321679d8bac9 100644 --- a/src/Workspaces/CoreTest/ChecksumTests.cs +++ b/src/Workspaces/CoreTest/ChecksumTests.cs @@ -177,7 +177,7 @@ public void DoNotProduceNullChecksum() Assert.NotEqual(Checksum.Null, Checksum.Create([""])); Assert.NotEqual(Checksum.Null, Checksum.Create(["\0"])); - Assert.NotEqual(Checksum.Null, Checksum.Create(new string?[] { null })); + Assert.NotEqual(Checksum.Null, Checksum.Create([null])); Assert.NotEqual(Checksum.Null, Checksum.Create(new MemoryStream())); Assert.NotEqual(Checksum.Null, Checksum.Create(stackalloc Checksum[] { Checksum.Null })); Assert.NotEqual(Checksum.Null, Checksum.Create(ImmutableArray.Create(Checksum.Null))); diff --git a/src/Workspaces/CoreTest/CodeCleanup/AddMissingTokensTests.cs b/src/Workspaces/CoreTest/CodeCleanup/AddMissingTokensTests.cs index ea3c5eeeb0594..be8c06f9a4dc0 100644 --- a/src/Workspaces/CoreTest/CodeCleanup/AddMissingTokensTests.cs +++ b/src/Workspaces/CoreTest/CodeCleanup/AddMissingTokensTests.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeCleanup.Providers; @@ -2717,7 +2718,7 @@ private static async Task VerifyAsync(string codeWithMarker, string expectedResu var document = CreateDocument(codeWithoutMarker, LanguageNames.VisualBasic); var codeCleanups = CodeCleaner.GetDefaultProviders(document).WhereAsArray(p => p.Name is PredefinedCodeCleanupProviderNames.AddMissingTokens or PredefinedCodeCleanupProviderNames.Format or PredefinedCodeCleanupProviderNames.Simplification); - var cleanDocument = await CodeCleaner.CleanupAsync(document, textSpans[0], CodeCleanupOptions.GetDefault(document.Project.Services), codeCleanups); + var cleanDocument = await CodeCleaner.CleanupAsync(document, textSpans[0], await document.GetCodeCleanupOptionsAsync(CancellationToken.None), codeCleanups); Assert.Equal(expectedResult, (await cleanDocument.GetSyntaxRootAsync()).ToFullString()); } @@ -2728,7 +2729,7 @@ private static Document CreateDocument(string code, string language) var projectId = ProjectId.CreateNewId(); var project = solution.AddProject(projectId, "Project", "Project.dll", language).GetProject(projectId); - return project.AddMetadataReference(TestMetadata.Net451.mscorlib) + return project.AddMetadataReference(NetFramework.mscorlib) .AddDocument("Document", SourceText.From(code)); } } diff --git a/src/Workspaces/CoreTest/CodeCleanup/CodeCleanupTests.cs b/src/Workspaces/CoreTest/CodeCleanup/CodeCleanupTests.cs index baf2a8c27fce4..86cb826d12a01 100644 --- a/src/Workspaces/CoreTest/CodeCleanup/CodeCleanupTests.cs +++ b/src/Workspaces/CoreTest/CodeCleanup/CodeCleanupTests.cs @@ -38,7 +38,7 @@ public void DefaultCSharpCodeCleanups() public async Task CodeCleanersCSharp_NoSpans() { var document = CreateDocument("class C { }", LanguageNames.CSharp); - var cleanDocument = await CodeCleaner.CleanupAsync(document, [], CodeCleanupOptions.GetDefault(document.Project.Services)); + var cleanDocument = await CodeCleaner.CleanupAsync(document, [], await document.GetCodeCleanupOptionsAsync(CancellationToken.None)); Assert.Equal(document, cleanDocument); } @@ -47,7 +47,7 @@ public async Task CodeCleanersCSharp_NoSpans() public async Task CodeCleanersCSharp_Document() { var document = CreateDocument("class C { }", LanguageNames.CSharp); - var cleanDocument = await CodeCleaner.CleanupAsync(document, CodeCleanupOptions.GetDefault(document.Project.Services)); + var cleanDocument = await CodeCleaner.CleanupAsync(document, await document.GetCodeCleanupOptionsAsync(CancellationToken.None)); Assert.Equal(document, cleanDocument); } @@ -57,7 +57,7 @@ public async Task CodeCleanersCSharp_Span() { var document = CreateDocument("class C { }", LanguageNames.CSharp); var root = await document.GetSyntaxRootAsync(); - var cleanDocument = await CodeCleaner.CleanupAsync(document, root.FullSpan, CodeCleanupOptions.GetDefault(document.Project.Services)); + var cleanDocument = await CodeCleaner.CleanupAsync(document, root.FullSpan, await document.GetCodeCleanupOptionsAsync(CancellationToken.None)); Assert.Equal(document, cleanDocument); } @@ -67,7 +67,7 @@ public async Task CodeCleanersCSharp_Spans() { var document = CreateDocument("class C { }", LanguageNames.CSharp); var root = await document.GetSyntaxRootAsync(); - var cleanDocument = await CodeCleaner.CleanupAsync(document, [root.FullSpan], CodeCleanupOptions.GetDefault(document.Project.Services)); + var cleanDocument = await CodeCleaner.CleanupAsync(document, [root.FullSpan], await document.GetCodeCleanupOptionsAsync(CancellationToken.None)); Assert.Equal(document, cleanDocument); } @@ -90,7 +90,7 @@ public async Task CodeCleanersVisualBasic_NoSpans() { var document = CreateDocument(@"Class C End Class", LanguageNames.VisualBasic); - var cleanDocument = await CodeCleaner.CleanupAsync(document, [], CodeCleanupOptions.GetDefault(document.Project.Services)); + var cleanDocument = await CodeCleaner.CleanupAsync(document, [], await document.GetCodeCleanupOptionsAsync(CancellationToken.None)); Assert.Equal(document, cleanDocument); } @@ -100,7 +100,7 @@ public async Task CodeCleanersVisualBasic_Document() { var document = CreateDocument(@"Class C End Class", LanguageNames.VisualBasic); - var cleanDocument = await CodeCleaner.CleanupAsync(document, CodeCleanupOptions.GetDefault(document.Project.Services)); + var cleanDocument = await CodeCleaner.CleanupAsync(document, await document.GetCodeCleanupOptionsAsync(CancellationToken.None)); Assert.Equal(document, cleanDocument); } @@ -111,7 +111,7 @@ public async Task CodeCleanersVisualBasic_Span() var document = CreateDocument(@"Class C End Class", LanguageNames.VisualBasic); var root = await document.GetSyntaxRootAsync(); - var cleanDocument = await CodeCleaner.CleanupAsync(document, root.FullSpan, CodeCleanupOptions.GetDefault(document.Project.Services)); + var cleanDocument = await CodeCleaner.CleanupAsync(document, root.FullSpan, await document.GetCodeCleanupOptionsAsync(CancellationToken.None)); Assert.Equal(document, cleanDocument); } @@ -122,7 +122,7 @@ public async Task CodeCleanersVisualBasic_Spans() var document = CreateDocument(@"Class C End Class", LanguageNames.VisualBasic); var root = await document.GetSyntaxRootAsync(); - var cleanDocument = await CodeCleaner.CleanupAsync(document, [root.FullSpan], CodeCleanupOptions.GetDefault(document.Project.Services)); + var cleanDocument = await CodeCleaner.CleanupAsync(document, [root.FullSpan], await document.GetCodeCleanupOptionsAsync(CancellationToken.None)); Assert.Equal(document, cleanDocument); } @@ -134,7 +134,7 @@ public async Task CodeCleanersCSharp_Annotation() var annotation = new SyntaxAnnotation(); document = document.WithSyntaxRoot((await document.GetSyntaxRootAsync()).WithAdditionalAnnotations(annotation)); - var cleanDocument = await CodeCleaner.CleanupAsync(document, annotation, CodeCleanupOptions.GetDefault(document.Project.Services)); + var cleanDocument = await CodeCleaner.CleanupAsync(document, annotation, await document.GetCodeCleanupOptionsAsync(CancellationToken.None)); Assert.Equal(document, cleanDocument); } @@ -147,7 +147,7 @@ public async Task CodeCleanersVisualBasic_Annotation() var annotation = new SyntaxAnnotation(); document = document.WithSyntaxRoot((await document.GetSyntaxRootAsync()).WithAdditionalAnnotations(annotation)); - var cleanDocument = await CodeCleaner.CleanupAsync(document, annotation, CodeCleanupOptions.GetDefault(document.Project.Services)); + var cleanDocument = await CodeCleaner.CleanupAsync(document, annotation, await document.GetCodeCleanupOptionsAsync(CancellationToken.None)); Assert.Equal(document, cleanDocument); } @@ -155,117 +155,113 @@ public async Task CodeCleanersVisualBasic_Annotation() #endregion [Fact] - public void EntireRange() + public Task EntireRange() => VerifyRange("{|b:{|r:class C {}|}|}"); [Fact] - public void EntireRange_Merge() + public Task EntireRange_Merge() => VerifyRange("{|r:class {|b:C { }|} class {|b: B { } |}|}"); [Fact] - public void EntireRange_EndOfFile() + public Task EntireRange_EndOfFile() => VerifyRange("{|r:class {|b:C { }|} class {|b: B { } |} |}"); [Fact] - public void EntireRangeWithTransformation_RemoveClass() + public async Task EntireRangeWithTransformation_RemoveClass() { - var expectedResult = (IEnumerable)null; var transformer = new MockCodeCleanupProvider() { - CleanupDocumentAsyncImpl = async (document, spans, options, cancellationToken) => + CleanupDocumentAsyncImpl = async (provider, document, spans, options, cancellationToken) => { var root = await document.GetSyntaxRootAsync(cancellationToken); root = root.RemoveCSharpMember(0); - expectedResult = [root.FullSpan]; + provider.ExpectedResult = [root.FullSpan]; return document.WithSyntaxRoot(root); } }; - VerifyRange("{|b:class C {}|}", transformer, ref expectedResult); + await VerifyRange("{|b:class C {}|}", transformer); } [Fact] - public void EntireRangeWithTransformation_AddMember() + public async Task EntireRangeWithTransformation_AddMember() { - var expectedResult = (IEnumerable)null; var transformer = new MockCodeCleanupProvider() { - CleanupDocumentAsyncImpl = async (document, spans, options, cancellationToken) => + CleanupDocumentAsyncImpl = async (provider, document, spans, options, cancellationToken) => { var root = await document.GetSyntaxRootAsync(cancellationToken); var @class = root.GetMember(0); var classWithMember = @class.AddCSharpMember(CreateCSharpMethod(), 0); root = root.ReplaceNode(@class, classWithMember); - expectedResult = [root.FullSpan]; + provider.ExpectedResult = [root.FullSpan]; return document.WithSyntaxRoot(root); } }; - VerifyRange("{|b:class C {}|}", transformer, ref expectedResult); + await VerifyRange("{|b:class C {}|}", transformer); } [Fact] - public void RangeWithTransformation_AddMember() + public async Task RangeWithTransformation_AddMember() { - var expectedResult = (IEnumerable)null; var transformer = new MockCodeCleanupProvider() { - CleanupDocumentAsyncImpl = async (document, spans, options, cancellationToken) => + CleanupDocumentAsyncImpl = async (provider, document, spans, options, cancellationToken) => { var root = await document.GetSyntaxRootAsync(cancellationToken); var @class = root.GetMember(0).GetMember(0); var classWithMember = @class.AddCSharpMember(CreateCSharpMethod(), 0); root = root.ReplaceNode(@class, classWithMember); - expectedResult = [root.GetMember(0).GetMember(0).GetCodeCleanupSpan()]; + provider.ExpectedResult = [root.GetMember(0).GetMember(0).GetCodeCleanupSpan()]; return document.WithSyntaxRoot(root); } }; - VerifyRange("namespace N { {|b:class C {}|} }", transformer, ref expectedResult); + await VerifyRange("namespace N { {|b:class C {}|} }", transformer); } [Fact] - public void RangeWithTransformation_RemoveMember() + public async Task RangeWithTransformation_RemoveMember() { - var expectedResult = (IEnumerable)null; var transformer = new MockCodeCleanupProvider() { - CleanupDocumentAsyncImpl = async (document, spans, options, cancellationToken) => + CleanupDocumentAsyncImpl = async (provider, document, spans, options, cancellationToken) => { var root = await document.GetSyntaxRootAsync(cancellationToken); var @class = root.GetMember(0).GetMember(0); var classWithMember = @class.RemoveCSharpMember(0); root = root.ReplaceNode(@class, classWithMember); - expectedResult = [root.GetMember(0).GetMember(0).GetCodeCleanupSpan()]; + provider.ExpectedResult = [root.GetMember(0).GetMember(0).GetCodeCleanupSpan()]; return document.WithSyntaxRoot(root); } }; - VerifyRange("namespace N { {|b:class C { void Method() { } }|} }", transformer, ref expectedResult); + await VerifyRange("namespace N { {|b:class C { void Method() { } }|} }", transformer); } [Fact] - public void MultipleRange_Overlapped() + public Task MultipleRange_Overlapped() => VerifyRange("namespace N {|r:{ {|b:class C { {|b:void Method() { }|} }|} }|}"); [Fact] - public void MultipleRange_Adjacent() + public Task MultipleRange_Adjacent() => VerifyRange("namespace N {|r:{ {|b:class C { |}{|b:void Method() { } }|} }|}"); [Fact] - public void MultipleRanges() + public Task MultipleRanges() => VerifyRange("namespace N { class C {|r:{ {|b:void Method() { }|} }|} class C2 {|r:{ {|b:void Method() { }|} }|} }"); [Fact, WorkItem(12848, "DevDiv_Projects/Roslyn")] - public void DoNotCrash_VB() + public async Task DoNotCrash_VB() { var code = @"#If DEBUG OrElse TRACE Then Imports System.Diagnostics @@ -281,7 +277,7 @@ Imports System.Diagnostics #End Region #End Region"; - VerifyRange(code, LanguageNames.VisualBasic); + await VerifyRange(code, LanguageNames.VisualBasic); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/774295")] @@ -318,12 +314,12 @@ End Class Assert.NotNull(newSemanticModel); Assert.True(newSemanticModel.IsSpeculativeSemanticModel); - var cleanDocument = await CodeCleaner.CleanupAsync(document, CodeCleanupOptions.GetDefault(document.Project.Services)); + var cleanDocument = await CodeCleaner.CleanupAsync(document, await document.GetCodeCleanupOptionsAsync(CancellationToken.None)); Assert.Equal(document, cleanDocument); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/547075")] - public void TestCodeCleanupWithinNonStructuredTrivia() + public async Task TestCodeCleanupWithinNonStructuredTrivia() { var code = @" #Const ccConst = 0 @@ -339,16 +335,15 @@ Sub Main(args As String()) End Sub End Module"; - VerifyRange(code, LanguageNames.VisualBasic); + await VerifyRange(code, LanguageNames.VisualBasic); } [Fact] - public void RangeWithTransformation_OutsideOfRange() + public async Task RangeWithTransformation_OutsideOfRange() { - var expectedResult = (IEnumerable)null; var transformer = new MockCodeCleanupProvider() { - CleanupDocumentAsyncImpl = async (document, spans, options, cancellationToken) => + CleanupDocumentAsyncImpl = async (provider, document, spans, options, cancellationToken) => { var root = await document.GetSyntaxRootAsync(cancellationToken); var member = root.GetMember(0).GetMember(0).GetMember(0); @@ -358,54 +353,57 @@ public void RangeWithTransformation_OutsideOfRange() root = root.ReplaceToken(previousToken, CSharp.SyntaxFactory.Identifier(previousToken.LeadingTrivia, previousToken.ValueText, previousToken.TrailingTrivia)); root = root.ReplaceToken(nextToken, CSharp.SyntaxFactory.Token(nextToken.LeadingTrivia, CSharp.CSharpExtensions.Kind(nextToken), nextToken.TrailingTrivia)); - expectedResult = []; + provider.ExpectedResult = []; return document.WithSyntaxRoot(root); } }; - VerifyRange("namespace N { class C { {|b:void Method() { }|} } }", transformer, ref expectedResult); + await VerifyRange("namespace N { class C { {|b:void Method() { }|} } }", transformer); } public static CSharp.Syntax.MethodDeclarationSyntax CreateCSharpMethod(string returnType = "void", string methodName = "Method") => CSharp.SyntaxFactory.MethodDeclaration(CSharp.SyntaxFactory.ParseTypeName(returnType), CSharp.SyntaxFactory.Identifier(methodName)); - private static void VerifyRange(string codeWithMarker, string language = LanguageNames.CSharp) + private static async Task VerifyRange(string codeWithMarker, string language = LanguageNames.CSharp) { MarkupTestFile.GetSpans(codeWithMarker, out var codeWithoutMarker, out IDictionary> namedSpans); var expectedResult = namedSpans.TryGetValue("r", out var spans) ? spans : SpecializedCollections.EmptyEnumerable(); - VerifyRange(codeWithoutMarker, [], namedSpans["b"], ref expectedResult, language); + var transformer = new MockCodeCleanupProvider { ExpectedResult = expectedResult }; + + await VerifyRange(codeWithoutMarker, [], namedSpans["b"], transformer, language); } - private static void VerifyRange(string codeWithMarker, ICodeCleanupProvider transformer, ref IEnumerable expectedResult, string language = LanguageNames.CSharp) + private static async Task VerifyRange(string codeWithMarker, MockCodeCleanupProvider transformer, string language = LanguageNames.CSharp) { MarkupTestFile.GetSpans(codeWithMarker, out var codeWithoutMarker, out IDictionary> namedSpans); - VerifyRange(codeWithoutMarker, [transformer], namedSpans["b"], ref expectedResult, language); + await VerifyRange(codeWithoutMarker, [transformer], namedSpans["b"], transformer, language); } - private static void VerifyRange(string code, ImmutableArray codeCleanups, ImmutableArray spans, ref IEnumerable expectedResult, string language) + private static async Task VerifyRange(string code, ImmutableArray codeCleanups, ImmutableArray spans, MockCodeCleanupProvider transformer, string language) { - var result = (IEnumerable)null; var spanCodeCleanup = new MockCodeCleanupProvider() { - CleanupDocumentAsyncImpl = (document, spans, options, cancellationToken) => + CleanupDocumentAsyncImpl = (provider, document, spans, options, cancellationToken) => { - result = spans; + provider.ExpectedResult = spans; return Task.FromResult(document); } }; var document = CreateDocument(code, language); - CodeCleaner.CleanupAsync(document, spans, CodeCleanupOptions.GetDefault(document.Project.Services), codeCleanups.Concat(spanCodeCleanup)).Wait(); + await CodeCleaner.CleanupAsync(document, spans, + await document.GetCodeCleanupOptionsAsync(CancellationToken.None), + codeCleanups.Concat(spanCodeCleanup)); - var sortedSpans = result.ToList(); - var expectedSpans = expectedResult.ToList(); + var sortedSpans = spanCodeCleanup.ExpectedResult.ToList(); + var expectedSpans = transformer.ExpectedResult.ToList(); sortedSpans.Sort(); expectedSpans.Sort(); diff --git a/src/Workspaces/CoreTest/CodeCleanup/FixIncorrectTokenTests.cs b/src/Workspaces/CoreTest/CodeCleanup/FixIncorrectTokenTests.cs index 9ab7b0d7800fc..130ace2e44034 100644 --- a/src/Workspaces/CoreTest/CodeCleanup/FixIncorrectTokenTests.cs +++ b/src/Workspaces/CoreTest/CodeCleanup/FixIncorrectTokenTests.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeCleanup.Providers; @@ -742,7 +743,7 @@ private static async Task VerifyAsync(string codeWithMarker, string expectedResu var document = CreateDocument(codeWithoutMarker, LanguageNames.VisualBasic); var codeCleanups = CodeCleaner.GetDefaultProviders(document).WhereAsArray(p => p.Name is PredefinedCodeCleanupProviderNames.FixIncorrectTokens or PredefinedCodeCleanupProviderNames.Format); - var cleanDocument = await CodeCleaner.CleanupAsync(document, textSpans[0], CodeCleanupOptions.GetDefault(document.Project.Services), codeCleanups); + var cleanDocument = await CodeCleaner.CleanupAsync(document, textSpans[0], await document.GetCodeCleanupOptionsAsync(CancellationToken.None), codeCleanups); Assert.Equal(expectedResult, (await cleanDocument.GetSyntaxRootAsync()).ToFullString()); } @@ -753,7 +754,7 @@ private static Document CreateDocument(string code, string language) var projectId = ProjectId.CreateNewId(); var project = solution.AddProject(projectId, "Project", "Project.dll", language).GetProject(projectId); - return project.AddMetadataReference(TestMetadata.Net451.mscorlib) + return project.AddMetadataReference(NetFramework.mscorlib) .AddDocument("Document", SourceText.From(code)); } } diff --git a/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs b/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs index 7c4357021d287..4984445d61f22 100644 --- a/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs +++ b/src/Workspaces/CoreTest/CodeCleanup/MockCodeCleanupProvider.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections; +using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -16,17 +18,15 @@ namespace Microsoft.CodeAnalysis.UnitTests.CodeCleanup { internal sealed class MockCodeCleanupProvider : ICodeCleanupProvider { - public Func, SyntaxFormattingOptions, CancellationToken, Task>? CleanupDocumentAsyncImpl { get; set; } - public Func, SyntaxFormattingOptions, SolutionServices, SyntaxNode>? CleanupNodeImpl { get; set; } + public IEnumerable ExpectedResult = null!; - public MockCodeCleanupProvider() - { - } + public Func, SyntaxFormattingOptions, CancellationToken, Task>? CleanupDocumentAsyncImpl { get; set; } + public Func, SyntaxFormattingOptions, SolutionServices, SyntaxNode>? CleanupNodeImpl { get; set; } public string Name => nameof(MockCodeCleanupProvider); public Task CleanupAsync(Document document, ImmutableArray spans, CodeCleanupOptions options, CancellationToken cancellationToken) - => (CleanupDocumentAsyncImpl ?? throw new NotImplementedException()).Invoke(document, spans, options.FormattingOptions, cancellationToken); + => (CleanupDocumentAsyncImpl ?? throw new NotImplementedException()).Invoke(this, document, spans, options.FormattingOptions, cancellationToken); public Task CleanupAsync(SyntaxNode root, ImmutableArray spans, SyntaxFormattingOptions options, SolutionServices services, CancellationToken cancellationToken) => Task.FromResult((CleanupNodeImpl ?? throw new NotImplementedException()).Invoke(root, spans, options, services)); diff --git a/src/Workspaces/CoreTest/CodeCleanup/NormalizeModifiersOrOperatorsTests.cs b/src/Workspaces/CoreTest/CodeCleanup/NormalizeModifiersOrOperatorsTests.cs index 5327e19d4a3b2..3a173727b342e 100644 --- a/src/Workspaces/CoreTest/CodeCleanup/NormalizeModifiersOrOperatorsTests.cs +++ b/src/Workspaces/CoreTest/CodeCleanup/NormalizeModifiersOrOperatorsTests.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeCleanup.Providers; @@ -1018,7 +1019,7 @@ private static async Task VerifyAsync(string codeWithMarker, string expectedResu var document = CreateDocument(codeWithoutMarker, LanguageNames.VisualBasic); var codeCleanups = CodeCleaner.GetDefaultProviders(document).WhereAsArray(p => p.Name is PredefinedCodeCleanupProviderNames.NormalizeModifiersOrOperators or PredefinedCodeCleanupProviderNames.Format); - var cleanDocument = await CodeCleaner.CleanupAsync(document, textSpans[0], CodeCleanupOptions.GetDefault(document.Project.Services), codeCleanups); + var cleanDocument = await CodeCleaner.CleanupAsync(document, textSpans[0], await document.GetCodeCleanupOptionsAsync(CancellationToken.None), codeCleanups); Assert.Equal(expectedResult, (await cleanDocument.GetSyntaxRootAsync()).ToFullString()); } diff --git a/src/Workspaces/CoreTest/CodeCleanup/ReduceTokenTests.cs b/src/Workspaces/CoreTest/CodeCleanup/ReduceTokenTests.cs index 2e3a58474cee3..e7b0192c68c5e 100644 --- a/src/Workspaces/CoreTest/CodeCleanup/ReduceTokenTests.cs +++ b/src/Workspaces/CoreTest/CodeCleanup/ReduceTokenTests.cs @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.UnitTests.CodeCleanup [Trait(Traits.Feature, Traits.Features.ReduceTokens)] public class ReduceTokenTests { -#if NETCOREAPP +#if NET private static bool IsNetCoreApp => true; #else private static bool IsNetCoreApp => false; @@ -2006,7 +2006,7 @@ private static async Task VerifyAsync(string codeWithMarker, string expectedResu var document = CreateDocument(codeWithoutMarker, LanguageNames.VisualBasic); var codeCleanups = CodeCleaner.GetDefaultProviders(document).WhereAsArray(p => p.Name is PredefinedCodeCleanupProviderNames.ReduceTokens or PredefinedCodeCleanupProviderNames.CaseCorrection or PredefinedCodeCleanupProviderNames.Format); - var cleanDocument = await CodeCleaner.CleanupAsync(document, textSpans[0], CodeCleanupOptions.GetDefault(document.Project.Services), codeCleanups); + var cleanDocument = await CodeCleaner.CleanupAsync(document, textSpans[0], await document.GetCodeCleanupOptionsAsync(CancellationToken.None), codeCleanups); AssertEx.EqualOrDiff(expectedResult, (await cleanDocument.GetSyntaxRootAsync()).ToFullString()); } @@ -2017,7 +2017,7 @@ private static Document CreateDocument(string code, string language) var projectId = ProjectId.CreateNewId(); var project = solution.AddProject(projectId, "Project", "Project.dll", language).GetProject(projectId); - return project.AddMetadataReference(TestMetadata.Net451.mscorlib) + return project.AddMetadataReference(NetFramework.mscorlib) .AddDocument("Document", SourceText.From(code)); } } diff --git a/src/Workspaces/CoreTest/CodeCleanup/RemoveUnnecessaryLineContinuationTests.cs b/src/Workspaces/CoreTest/CodeCleanup/RemoveUnnecessaryLineContinuationTests.cs index 4b5a2c31e6c13..2ba8121d55bfd 100644 --- a/src/Workspaces/CoreTest/CodeCleanup/RemoveUnnecessaryLineContinuationTests.cs +++ b/src/Workspaces/CoreTest/CodeCleanup/RemoveUnnecessaryLineContinuationTests.cs @@ -1441,7 +1441,7 @@ private static async Task VerifyAsync(string codeWithMarker, string expectedResu var document = CreateDocument(codeWithoutMarker, LanguageNames.VisualBasic, langVersion); var codeCleanups = CodeCleaner.GetDefaultProviders(document).WhereAsArray(p => p.Name is PredefinedCodeCleanupProviderNames.RemoveUnnecessaryLineContinuation or PredefinedCodeCleanupProviderNames.Format); - var cleanDocument = await CodeCleaner.CleanupAsync(document, textSpans[0], CodeCleanupOptions.GetDefault(document.Project.Services), codeCleanups); + var cleanDocument = await CodeCleaner.CleanupAsync(document, textSpans[0], await document.GetCodeCleanupOptionsAsync(CancellationToken.None), codeCleanups); var actualResult = (await cleanDocument.GetRequiredSyntaxRootAsync(CancellationToken.None)).ToFullString(); AssertEx.EqualOrDiff(expectedResult, actualResult); diff --git a/src/Workspaces/CoreTest/FindReferencesTests.cs b/src/Workspaces/CoreTest/FindReferencesTests.cs index e1bd83a3a3702..45edebba88936 100644 --- a/src/Workspaces/CoreTest/FindReferencesTests.cs +++ b/src/Workspaces/CoreTest/FindReferencesTests.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Test.Utilities; @@ -23,6 +24,22 @@ public class FindReferencesTests : TestBase private static Workspace CreateWorkspace(Type[] additionalParts = null) => new AdhocWorkspace(FeaturesTestCompositions.Features.AddParts(additionalParts).GetHostServices()); + private static Solution AddProjectWithMetadataReferences(Solution solution, string projectName, string languageName, string code, IEnumerable metadataReference, params ProjectId[] projectReferences) + { + var suffix = languageName == LanguageNames.CSharp ? "cs" : "vb"; + var pid = ProjectId.CreateNewId(); + var did = DocumentId.CreateNewId(pid); + var pi = ProjectInfo.Create( + pid, + VersionStamp.Default, + projectName, + projectName, + languageName, + metadataReferences: metadataReference, + projectReferences: projectReferences.Select(p => new ProjectReference(p))); + return solution.AddProject(pi).AddDocument(did, $"{projectName}.{suffix}", SourceText.From(code)); + } + private static Solution AddProjectWithMetadataReferences(Solution solution, string projectName, string languageName, string code, MetadataReference metadataReference, params ProjectId[] projectReferences) { var suffix = languageName == LanguageNames.CSharp ? "cs" : "vb"; @@ -105,7 +122,7 @@ public class C { var solution = workspace.CurrentSolution .AddProject(pid, "goo", "goo.dll", LanguageNames.CSharp) .AddMetadataReference(pid, MscorlibRef) - .AddMetadataReference(pid, ((PortableExecutableReference)MscorlibRef).WithAliases(new[] { "X" })) + .AddMetadataReference(pid, ((PortableExecutableReference)MscorlibRef).WithAliases(["X"])) .AddDocument(did, "goo.cs", SourceText.From(text)); var project = solution.Projects.First(); @@ -352,9 +369,9 @@ public interface I { System.Uri Get(); } -}", NetStandard20Ref); +}", NetStandard20.References.All); - solution = AddProjectWithMetadataReferences(solution, "DesktopProject", LanguageNames.CSharp, @" + solution = AddProjectWithMetadataReferences(solution, "NetCoreProject", LanguageNames.CSharp, @" using N; namespace N2 @@ -366,12 +383,9 @@ public System.Uri Get() return null; } } -}", SystemRef_v46, solution.Projects.Single(pid => pid.Name == "NetStandardProject").Id); - - var desktopProject = solution.Projects.First(p => p.Name == "DesktopProject"); - solution = solution.AddMetadataReferences(desktopProject.Id, [MscorlibRef_v46, Net46StandardFacade]); +}", NetCoreApp.References, solution.Projects.Single(pid => pid.Name == "NetStandardProject").Id); - desktopProject = solution.GetProject(desktopProject.Id); + var netCoreProject = solution.Projects.First(p => p.Name == "NetCoreProject"); var netStandardProject = solution.Projects.First(p => p.Name == "NetStandardProject"); var interfaceMethod = (IMethodSymbol)(await netStandardProject.GetCompilationAsync()).GetTypeByMetadataName("N.I").GetMembers("Get").First(); @@ -383,7 +397,7 @@ public System.Uri Get() foreach (var r in references) projectIds.Add(solution.GetOriginatingProjectId(r.Definition)); - Assert.True(projectIds.Contains(desktopProject.Id)); + Assert.True(projectIds.Contains(netCoreProject.Id)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35786")] @@ -416,7 +430,7 @@ interface ITestBase using var workspace = CreateWorkspace(); var solution = GetMultipleDocumentSolution(workspace, [implText, interface1Text, interface2Text]); - solution = solution.AddMetadataReferences(solution.ProjectIds.Single(), [MscorlibRef_v46, Net46StandardFacade, SystemRef_v46, NetStandard20Ref]); + solution = solution.AddMetadataReferences(solution.ProjectIds.Single(), NetFramework.References); var project = solution.Projects.Single(); var compilation = await project.GetCompilationAsync(); @@ -447,7 +461,7 @@ public class BaseClass public virtual void SomeMethod() { } } } -", MscorlibRefPortable); +", MscorlibPP7Ref); // create a normal assembly with a type derived from the portable base and overriding the method solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.CSharp, @" @@ -459,7 +473,7 @@ public class DerivedClass : BaseClass public override void SomeMethod() { } } } -", MscorlibRef, solution.Projects.Single(pid => pid.Name == "PortableProject").Id); +", Net40.References.mscorlib, solution.Projects.Single(pid => pid.Name == "PortableProject").Id); // get symbols for methods var portableCompilation = await solution.Projects.Single(p => p.Name == "PortableProject").GetCompilationAsync(); diff --git a/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs b/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs index 1b771b5110037..0e9c68fc1b5bb 100644 --- a/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs +++ b/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs @@ -231,12 +231,11 @@ public void OptionsAreMessagePackSerializable(string language) var options = new object[] { - SimplifierOptions.GetDefault(languageServices), - SyntaxFormattingOptions.GetDefault(languageServices), - CodeCleanupOptions.GetDefault(languageServices), - CodeGenerationOptions.GetDefault(languageServices), - CodeActionOptions.Default, - IndentationOptions.GetDefault(languageServices), + SimplifierOptionsProviders.GetDefault(languageServices), + SyntaxFormattingOptionsProviders.GetDefault(languageServices), + CodeCleanupOptionsProviders.GetDefault(languageServices), + CodeGenerationOptionsProviders.GetDefault(languageServices), + IndentationOptionsProviders.GetDefault(languageServices), ExtractMethodGenerationOptions.GetDefault(languageServices), // some non-default values: diff --git a/src/Workspaces/CoreTest/SemanticModelReuse/SemanticModelReuseTests.cs b/src/Workspaces/CoreTest/SemanticModelReuse/SemanticModelReuseTests.cs index a7d88427a2a5f..4c82972f50325 100644 --- a/src/Workspaces/CoreTest/SemanticModelReuse/SemanticModelReuseTests.cs +++ b/src/Workspaces/CoreTest/SemanticModelReuse/SemanticModelReuseTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.UnitTests.SemanticModelReuse { @@ -25,7 +26,7 @@ private static Document CreateDocument(string code, string language) var projectId = ProjectId.CreateNewId(); var project = solution.AddProject(projectId, "Project", "Project.dll", language).GetProject(projectId); - return project.AddMetadataReference(TestMetadata.Net40.mscorlib) + return project.AddMetadataReference(Net40.References.mscorlib) .AddDocument("Document", SourceText.From(code)); } diff --git a/src/Workspaces/CoreTest/SolutionTests/DocumentInfoTests.cs b/src/Workspaces/CoreTest/SolutionTests/DocumentInfoTests.cs index 8fc146789addb..037488fcf5d36 100644 --- a/src/Workspaces/CoreTest/SolutionTests/DocumentInfoTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/DocumentInfoTests.cs @@ -77,7 +77,7 @@ public void Create_Folders() var info2 = DocumentInfo.Create(documentId, "doc"); Assert.True(((ImmutableArray)info2.Folders).IsEmpty); - var info3 = DocumentInfo.Create(documentId, "doc", folders: new string[0]); + var info3 = DocumentInfo.Create(documentId, "doc", folders: []); Assert.True(((ImmutableArray)info3.Folders).IsEmpty); var info4 = DocumentInfo.Create(documentId, "doc", folders: []); diff --git a/src/Workspaces/CoreTest/SolutionTests/ProjectInfoTests.cs b/src/Workspaces/CoreTest/SolutionTests/ProjectInfoTests.cs index 30b9912cc3c94..92f2091cc21e4 100644 --- a/src/Workspaces/CoreTest/SolutionTests/ProjectInfoTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/ProjectInfoTests.cs @@ -26,7 +26,7 @@ public void Create_Errors_NullReferences() Assert.Throws(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: null)); Assert.Throws(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: "C#", - documents: new DocumentInfo[] { null })); + documents: [null])); } [Fact] @@ -39,31 +39,31 @@ public void Create_Errors_DuplicateItems() () => ProjectInfo.Create(pid, VersionStamp.Default, "proj", "assembly", "C#", documents: [documentInfo, documentInfo])); Assert.Throws(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: "C#", - additionalDocuments: new DocumentInfo[] { null })); + additionalDocuments: [null])); Assert.Throws("additionalDocuments[1]", () => ProjectInfo.Create(pid, VersionStamp.Default, "proj", "assembly", "C#", additionalDocuments: [documentInfo, documentInfo])); Assert.Throws(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: "C#", - projectReferences: new ProjectReference[] { null })); + projectReferences: [null])); var projectReference = new ProjectReference(ProjectId.CreateNewId()); Assert.Throws("projectReferences[1]", () => ProjectInfo.Create(pid, VersionStamp.Default, "proj", "assembly", "C#", projectReferences: [projectReference, projectReference])); Assert.Throws("analyzerReferences[0]", () => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: "C#", - analyzerReferences: new AnalyzerReference[] { null })); + analyzerReferences: [null])); var analyzerReference = new TestAnalyzerReference(); Assert.Throws("analyzerReferences[1]", - () => ProjectInfo.Create(pid, VersionStamp.Default, "proj", "assembly", "C#", analyzerReferences: new[] { analyzerReference, analyzerReference })); + () => ProjectInfo.Create(pid, VersionStamp.Default, "proj", "assembly", "C#", analyzerReferences: [analyzerReference, analyzerReference])); Assert.Throws(() => ProjectInfo.Create(pid, VersionStamp.Default, name: "Goo", assemblyName: "Bar", language: "C#", - metadataReferences: new MetadataReference[] { null })); + metadataReferences: [null])); var metadataReference = new TestMetadataReference(); Assert.Throws("metadataReferences[1]", - () => ProjectInfo.Create(pid, VersionStamp.Default, "proj", "assembly", "C#", metadataReferences: new[] { metadataReference, metadataReference })); + () => ProjectInfo.Create(pid, VersionStamp.Default, "proj", "assembly", "C#", metadataReferences: [metadataReference, metadataReference])); } [Fact] @@ -78,7 +78,7 @@ public void Create_Documents() var info2 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#"); Assert.True(((ImmutableArray)info2.Documents).IsEmpty); - var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", documents: new DocumentInfo[0]); + var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", documents: []); Assert.True(((ImmutableArray)info3.Documents).IsEmpty); var info4 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", documents: []); @@ -97,7 +97,7 @@ public void Create_AdditionalDocuments() var info2 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#"); Assert.True(((ImmutableArray)info2.AdditionalDocuments).IsEmpty); - var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", additionalDocuments: new DocumentInfo[0]); + var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", additionalDocuments: []); Assert.True(((ImmutableArray)info3.AdditionalDocuments).IsEmpty); var info4 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", additionalDocuments: []); @@ -116,7 +116,7 @@ public void Create_ProjectReferences() var info2 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#"); Assert.True(((ImmutableArray)info2.ProjectReferences).IsEmpty); - var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", projectReferences: new ProjectReference[0]); + var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", projectReferences: []); Assert.True(((ImmutableArray)info3.ProjectReferences).IsEmpty); var info4 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", projectReferences: []); @@ -129,13 +129,13 @@ public void Create_MetadataReferences() var version = VersionStamp.Default; var metadataReference = new TestMetadataReference(); - var info1 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", metadataReferences: new[] { metadataReference }); + var info1 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", metadataReferences: [metadataReference]); Assert.Same(metadataReference, ((ImmutableArray)info1.MetadataReferences).Single()); var info2 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#"); Assert.True(((ImmutableArray)info2.MetadataReferences).IsEmpty); - var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", metadataReferences: new MetadataReference[0]); + var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", metadataReferences: []); Assert.True(((ImmutableArray)info3.MetadataReferences).IsEmpty); var info4 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", metadataReferences: []); @@ -148,13 +148,13 @@ public void Create_AnalyzerReferences() var version = VersionStamp.Default; var analyzerReference = new TestAnalyzerReference(); - var info1 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", analyzerReferences: new[] { analyzerReference }); + var info1 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", analyzerReferences: [analyzerReference]); Assert.Same(analyzerReference, ((ImmutableArray)info1.AnalyzerReferences).Single()); var info2 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#"); Assert.True(((ImmutableArray)info2.AnalyzerReferences).IsEmpty); - var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", analyzerReferences: new AnalyzerReference[0]); + var info3 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", analyzerReferences: []); Assert.True(((ImmutableArray)info3.AnalyzerReferences).IsEmpty); var info4 = ProjectInfo.Create(ProjectId.CreateNewId(), version, "proj", "assembly", "C#", analyzerReferences: []); @@ -182,6 +182,7 @@ public void TestProperties() var documentInfo = DocumentInfo.Create(DocumentId.CreateNewId(projectId), "doc"); var instance = ProjectInfo.Create(name: "Name", id: ProjectId.CreateNewId(), version: VersionStamp.Default, assemblyName: "AssemblyName", language: "C#"); + SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithId(value), opt => opt.Id, ProjectId.CreateNewId(), defaultThrows: true); SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithVersion(value), opt => opt.Version, VersionStamp.Create()); SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithName(value), opt => opt.Name, "New", defaultThrows: true); SolutionTestHelpers.TestProperty(instance, (old, value) => old.WithAssemblyName(value), opt => opt.AssemblyName, "New", defaultThrows: true); diff --git a/src/Workspaces/CoreTest/SolutionTests/SolutionInfoTests.cs b/src/Workspaces/CoreTest/SolutionTests/SolutionInfoTests.cs index b09f8b0032c11..086b24797869c 100644 --- a/src/Workspaces/CoreTest/SolutionTests/SolutionInfoTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/SolutionInfoTests.cs @@ -37,7 +37,7 @@ public void Create_Projects() var info2 = SolutionInfo.Create(solutionId, version); Assert.True(((ImmutableArray)info2.Projects).IsEmpty); - var info3 = SolutionInfo.Create(solutionId, version, projects: new ProjectInfo[0]); + var info3 = SolutionInfo.Create(solutionId, version, projects: []); Assert.True(((ImmutableArray)info3.Projects).IsEmpty); var info4 = SolutionInfo.Create(solutionId, version, projects: []); diff --git a/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs b/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs index b068688cc7798..d328c2be37edd 100644 --- a/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/SolutionTests.cs @@ -17,6 +17,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; @@ -45,7 +46,7 @@ public class SolutionTests : TestBase { #nullable enable private static readonly string s_projectDir = Path.GetDirectoryName(typeof(SolutionTests).Assembly.Location)!; - private static readonly MetadataReference s_mscorlib = TestMetadata.Net451.mscorlib; + private static readonly MetadataReference s_mscorlib = NetFramework.mscorlib; private static readonly DocumentId s_unrelatedDocumentId = DocumentId.CreateNewId(ProjectId.CreateNewId()); private static Workspace CreateWorkspaceWithProjectAndDocuments(string? editorConfig = null) @@ -201,8 +202,8 @@ public void WithDocumentFolders() Assert.Same(newSolution2, newSolution1); // empty: - var newSolution3 = solution.WithDocumentFolders(documentId, new string[0]); - Assert.Equal(new string[0], newSolution3.GetDocument(documentId)!.Folders); + var newSolution3 = solution.WithDocumentFolders(documentId, []); + Assert.Equal([], newSolution3.GetDocument(documentId)!.Folders); var newSolution4 = solution.WithDocumentFolders(documentId, []); Assert.Same(newSolution3, newSolution4); @@ -210,7 +211,7 @@ public void WithDocumentFolders() var newSolution5 = solution.WithDocumentFolders(documentId, null); Assert.Same(newSolution3, newSolution5); - Assert.Throws(() => solution.WithDocumentFolders(documentId, folders: new string[] { null! })); + Assert.Throws(() => solution.WithDocumentFolders(documentId, folders: [null!])); Assert.Throws(() => solution.WithDocumentFolders(null!, folders)); Assert.Throws(() => solution.WithDocumentFolders(s_unrelatedDocumentId, folders)); @@ -227,7 +228,7 @@ public void WithDocumentFilePath() var newSolution1 = solution.WithDocumentFilePath(documentId, path); Assert.Equal(path, newSolution1.GetRequiredDocument(documentId).FilePath); - AssertEx.Equal(new[] { documentId }, newSolution1.GetDocumentIdsWithFilePath(path)); + AssertEx.Equal([documentId], newSolution1.GetDocumentIdsWithFilePath(path)); var newSolution2 = newSolution1.WithDocumentFilePath(documentId, path); Assert.Same(newSolution1, newSolution2); @@ -254,7 +255,7 @@ public void WithSourceCodeKind() Assert.Same(solution, solution.WithDocumentSourceCodeKind(documentId, SourceCodeKind.Regular)); var newSolution1 = solution.WithDocumentSourceCodeKind(documentId, SourceCodeKind.Script); - Assert.Equal(SourceCodeKind.Script, newSolution1.GetDocument(documentId)!.SourceCodeKind); + Assert.Equal(SourceCodeKind.Script, newSolution1.GetRequiredDocument(documentId).SourceCodeKind); Assert.Throws(() => solution.WithDocumentSourceCodeKind(documentId, (SourceCodeKind)(-1))); @@ -262,6 +263,26 @@ public void WithSourceCodeKind() Assert.Throws(() => solution.WithDocumentSourceCodeKind(s_unrelatedDocumentId, SourceCodeKind.Script)); } + [Fact] + public void WithSourceCodeKind_ParseOptions() + { + using var workspace = CreateWorkspaceWithProjectAndDocuments(); + + var solution = workspace.CurrentSolution; + var documentId = solution.Projects.Single().DocumentIds.Single(); + var projectId = documentId.ProjectId; + + solution = solution.WithProjectParseOptions(projectId, CSharpParseOptions.Default.WithKind(SourceCodeKind.Script)); + + var document1 = solution.GetRequiredDocument(documentId); + Assert.Equal(SourceCodeKind.Script, document1.DocumentState.ParseOptions?.Kind); + Assert.Equal(SourceCodeKind.Script, document1.SourceCodeKind); + + var document2 = document1.WithSourceCodeKind(SourceCodeKind.Regular); + Assert.Equal(SourceCodeKind.Regular, document2.DocumentState.ParseOptions?.Kind); + Assert.Equal(SourceCodeKind.Regular, document2.SourceCodeKind); + } + [Fact, Obsolete("Testing obsolete API")] public void WithSourceCodeKind_Obsolete() { @@ -384,8 +405,8 @@ public void WithDocumentText_MultipleDocuments() Assert.Same(newSolution1, newSolution2); // documents not in solution are skipped: https://github.com/dotnet/roslyn/issues/42029 - Assert.Same(solution, solution.WithDocumentText(new DocumentId[] { null! }, text)); - Assert.Same(solution, solution.WithDocumentText(new DocumentId[] { s_unrelatedDocumentId }, text)); + Assert.Same(solution, solution.WithDocumentText([null!], text)); + Assert.Same(solution, solution.WithDocumentText([s_unrelatedDocumentId], text)); Assert.Throws(() => solution.WithDocumentText((DocumentId[])null!, text, PreservationMode.PreserveIdentity)); Assert.Throws(() => solution.WithDocumentText([documentId], null!, PreservationMode.PreserveIdentity)); @@ -960,6 +981,362 @@ public void WithAnalyzerConfigDocumentTextLoader() Assert.Throws(() => solution.WithAnalyzerConfigDocumentTextLoader(s_unrelatedDocumentId, loader, PreservationMode.PreserveIdentity)); } + [Fact] + public void WithProjectInfo() + { + var projectId = ProjectId.CreateNewId(); + var projectId2 = ProjectId.CreateNewId(); + + using var workspace = CreateWorkspace(); + + var d1 = DocumentId.CreateNewId(projectId); + var d2 = DocumentId.CreateNewId(projectId); + var d3 = DocumentId.CreateNewId(projectId); + var a1 = DocumentId.CreateNewId(projectId); + var a2 = DocumentId.CreateNewId(projectId); + var a3 = DocumentId.CreateNewId(projectId); + var c1 = DocumentId.CreateNewId(projectId); + var c2 = DocumentId.CreateNewId(projectId); + var c3 = DocumentId.CreateNewId(projectId); + + var solution = workspace.CurrentSolution + .AddProject(ProjectInfo.Create(projectId, VersionStamp.Default, "proj1", "proj1", LanguageNames.CSharp, Path.Combine(s_projectDir, "proj1.dll"))) + .AddProject(ProjectInfo.Create(projectId2, VersionStamp.Default, "proj2", "proj2", LanguageNames.CSharp, Path.Combine(s_projectDir, "proj2.dll"))) + .AddDocument(d1, "d1.cs", SourceText.From("class D1;", Encoding.UTF8, SourceHashAlgorithms.Default), filePath: Path.Combine(s_projectDir, "d1.cs")) + .AddDocument(d2, "d2.cs", SourceText.From("class D2;", Encoding.UTF8, SourceHashAlgorithms.Default), filePath: Path.Combine(s_projectDir, "d2.cs")) + .AddAdditionalDocument(a1, "a1.txt", SourceText.From("text1", Encoding.UTF8, SourceHashAlgorithms.Default)) + .AddAdditionalDocument(a2, "a2.txt", SourceText.From("text2", Encoding.UTF8, SourceHashAlgorithms.Default)) + .AddAnalyzerConfigDocument(c1, "c1", SourceText.From("#empty1", Encoding.UTF8, SourceHashAlgorithms.Default), filePath: Path.Combine(s_projectDir, "editorcfg")) + .AddAnalyzerConfigDocument(c2, "c2", SourceText.From("#empty2", Encoding.UTF8, SourceHashAlgorithms.Default), filePath: Path.Combine(s_projectDir, "editorcfg")); + + var oldProject = solution.GetRequiredProject(projectId); + var documentIds = oldProject.DocumentIds; + + var newDocumentInfo1 = DocumentInfo.Create( + d1, + name: "newD1", + folders: ["f", "g"], + sourceCodeKind: SourceCodeKind.Script, + loader: TextLoader.From(TextAndVersion.Create(SourceText.From("class NewD1;", Encoding.UTF32, SourceHashAlgorithm.Sha256), VersionStamp.Create(), filePath: Path.Combine(s_projectDir, "newD1.cs"))), + filePath: Path.Combine(s_projectDir, "newD1.cs"), + isGenerated: true); + + var newDocumentInfo3 = DocumentInfo.Create( + d3, + name: "newD3", + folders: null, + sourceCodeKind: SourceCodeKind.Regular, + loader: TextLoader.From(TextAndVersion.Create(SourceText.From("class NewD3;", Encoding.UTF8, SourceHashAlgorithms.Default), VersionStamp.Create(), filePath: Path.Combine(s_projectDir, "newD3.cs"))), + filePath: Path.Combine(s_projectDir, "newD3.cs"), + isGenerated: false) + .WithDocumentServiceProvider(new TestDocumentServiceProvider()); + + var newAddDocumentInfo1 = DocumentInfo.Create( + a1, + name: "newA1", + folders: ["af", "ag"], + sourceCodeKind: SourceCodeKind.Script, + loader: TextLoader.From(TextAndVersion.Create(SourceText.From("new text1", Encoding.UTF32, SourceHashAlgorithm.Sha256), VersionStamp.Create(), filePath: Path.Combine(s_projectDir, "newD1.cs"))), + filePath: Path.Combine(s_projectDir, "newA1.txt"), + isGenerated: true); + + var newAddDocumentInfo3 = DocumentInfo.Create( + a3, + name: "newA3", + folders: null, + sourceCodeKind: SourceCodeKind.Regular, + loader: TextLoader.From(TextAndVersion.Create(SourceText.From("new text3", Encoding.UTF8, SourceHashAlgorithms.Default), VersionStamp.Create(), filePath: Path.Combine(s_projectDir, "newD3.cs"))), + filePath: Path.Combine(s_projectDir, "newA3.txt"), + isGenerated: false) + .WithDocumentServiceProvider(new TestDocumentServiceProvider()); + + var newConfigDocumentInfo1 = DocumentInfo.Create( + c1, + name: "newC1", + folders: ["cf", "cg"], + sourceCodeKind: SourceCodeKind.Script, + loader: TextLoader.From(TextAndVersion.Create(SourceText.From("#new empty1", Encoding.UTF32, SourceHashAlgorithm.Sha256), VersionStamp.Create(), filePath: Path.Combine(s_projectDir, "newD1.cs"))), + filePath: Path.Combine(s_projectDir, "newC1"), + isGenerated: true); + + var newConfigDocumentInfo3 = DocumentInfo.Create( + c3, + name: "newC3", + folders: null, + sourceCodeKind: SourceCodeKind.Regular, + loader: TextLoader.From(TextAndVersion.Create(SourceText.From("#new empty3", Encoding.UTF8, SourceHashAlgorithms.Default), VersionStamp.Create(), filePath: Path.Combine(s_projectDir, "newD3.cs"))), + filePath: Path.Combine(s_projectDir, "newC3"), + isGenerated: false) + .WithDocumentServiceProvider(new TestDocumentServiceProvider()); + + var metadataReference = MetadataReference.CreateFromImage([], filePath: "meta"); + var projectReference = new ProjectReference(projectId2); + var analyzerReference = new TestAnalyzerReference(); + + var newInfo = ProjectInfo.Create( + projectId, + VersionStamp.Create(), + name: "newProjectName", + assemblyName: "newAssemblyName", + language: LanguageNames.CSharp, + filePath: "newFilePath.cs", + outputFilePath: "newOutputFilePath", + outputRefFilePath: "newOutputRef", + compilationOptions: new CSharpCompilationOptions(OutputKind.WindowsApplication, moduleName: "newModuleName"), + parseOptions: new CSharpParseOptions(CS.LanguageVersion.CSharp5), + documents: + [ + // update existing document: + newDocumentInfo1, + // add new document: + newDocumentInfo3, + // remove existing document (d2) + ], + additionalDocuments: + [ + // update existing document: + newAddDocumentInfo1, + // add new document: + newAddDocumentInfo3, + // remove existing document (a2) + ], + projectReferences: [projectReference], + metadataReferences: [metadataReference], + analyzerReferences: [analyzerReference], + isSubmission: false, + hostObjectType: null) + .WithAnalyzerConfigDocuments( + [ + // update existing document: + newConfigDocumentInfo1, + // add new document: + newConfigDocumentInfo3, + // remove existing document (c2) + ]); + + var newSolution = solution.WithProjectInfo(newInfo); + var newProject = newSolution.GetRequiredProject(projectId); + + // attributes: + Assert.True(newProject.Version.GetTestAccessor().IsNewerThan(oldProject.Version)); + Assert.Equal(newInfo.Name, newProject.Name); + Assert.Equal(newInfo.AssemblyName, newProject.AssemblyName); + Assert.Equal(newInfo.Language, newProject.Language); + Assert.Equal(newInfo.FilePath, newProject.FilePath); + Assert.Equal(newInfo.OutputFilePath, newProject.OutputFilePath); + Assert.Equal(newInfo.CompilationOptions!.OutputKind, newProject.CompilationOptions!.OutputKind); + Assert.Equal(newInfo.CompilationOptions!.ModuleName, newProject.CompilationOptions!.ModuleName); + Assert.Equal(newInfo.ParseOptions!.LanguageVersion, newProject.ParseOptions!.LanguageVersion); + Assert.Equal(newInfo.OutputRefFilePath, newProject.OutputRefFilePath); + + AssertEx.AreEqual([projectReference], newProject.ProjectReferences); + AssertEx.AreEqual([metadataReference], newProject.MetadataReferences); + AssertEx.AreEqual([analyzerReference], newProject.AnalyzerReferences); + + // documents: + AssertEx.SetEqual([d1, d3], newProject.DocumentIds); + + var newDocument1 = newProject.GetRequiredDocument(d1); + var newText1 = newDocument1.GetTextSynchronously(CancellationToken.None); + Assert.Equal(newDocumentInfo1.Name, newDocument1.Name); + Assert.Equal(newDocumentInfo1.FilePath, newDocument1.FilePath); + Assert.Same(DefaultTextDocumentServiceProvider.Instance, newDocument1.DocumentServiceProvider); + Assert.Equal("class NewD1;", newText1.ToString()); + Assert.Same(Encoding.UTF32, newText1.Encoding); + Assert.Equal(SourceHashAlgorithm.Sha256, newText1.ChecksumAlgorithm); + + var newDocument3 = newProject.GetRequiredDocument(d3); + var newText3 = newDocument3.GetTextSynchronously(CancellationToken.None); + Assert.Equal(newDocumentInfo3.Name, newDocument3.Name); + Assert.Equal(newDocumentInfo3.FilePath, newDocument3.FilePath); + Assert.Same(newDocumentInfo3.DocumentServiceProvider, newDocument3.DocumentServiceProvider); + Assert.Equal("class NewD3;", newDocument3.GetTextSynchronously(CancellationToken.None).ToString()); + Assert.Same(Encoding.UTF8, newText3.Encoding); + Assert.Equal(SourceHashAlgorithms.Default, newText3.ChecksumAlgorithm); + + // additional documents: + AssertEx.SetEqual([a1, a3], newProject.AdditionalDocumentIds); + + var newAddDocument1 = newProject.GetRequiredAdditionalDocument(a1); + var newAddText1 = newAddDocument1.GetTextSynchronously(CancellationToken.None); + Assert.Equal(newAddDocumentInfo1.Name, newAddDocument1.Name); + Assert.Equal(newAddDocumentInfo1.FilePath, newAddDocument1.FilePath); + Assert.Same(DefaultTextDocumentServiceProvider.Instance, newAddDocument1.DocumentServiceProvider); + Assert.Equal("new text1", newAddText1.ToString()); + Assert.Same(Encoding.UTF32, newAddText1.Encoding); + Assert.Equal(SourceHashAlgorithm.Sha256, newAddText1.ChecksumAlgorithm); + + var newAddDocument3 = newProject.GetRequiredAdditionalDocument(a3); + var newAddText3 = newAddDocument3.GetTextSynchronously(CancellationToken.None); + Assert.Equal(newAddDocumentInfo3.Name, newAddDocument3.Name); + Assert.Equal(newAddDocumentInfo3.FilePath, newAddDocument3.FilePath); + Assert.Same(newAddDocumentInfo3.DocumentServiceProvider, newAddDocument3.DocumentServiceProvider); + Assert.Equal("new text3", newAddDocument3.GetTextSynchronously(CancellationToken.None).ToString()); + Assert.Same(Encoding.UTF8, newAddText3.Encoding); + Assert.Equal(SourceHashAlgorithms.Default, newAddText3.ChecksumAlgorithm); + + // analyzer config documents: + AssertEx.SetEqual([c1, c3], newProject.AnalyzerConfigDocumentIds); + + var newConfigDocument1 = newProject.GetRequiredAnalyzerConfigDocument(c1); + var newConfigText1 = newConfigDocument1.GetTextSynchronously(CancellationToken.None); + Assert.Equal(newConfigDocumentInfo1.Name, newConfigDocument1.Name); + Assert.Equal(newConfigDocumentInfo1.FilePath, newConfigDocument1.FilePath); + Assert.Same(DefaultTextDocumentServiceProvider.Instance, newConfigDocument1.DocumentServiceProvider); + Assert.Equal("#new empty1", newConfigText1.ToString()); + Assert.Same(Encoding.UTF32, newConfigText1.Encoding); + Assert.Equal(SourceHashAlgorithm.Sha256, newConfigText1.ChecksumAlgorithm); + + var newConfigDocument3 = newProject.GetRequiredAnalyzerConfigDocument(c3); + var newConfigText3 = newConfigDocument3.GetTextSynchronously(CancellationToken.None); + Assert.Equal(newConfigDocumentInfo3.Name, newConfigDocument3.Name); + Assert.Equal(newConfigDocumentInfo3.FilePath, newConfigDocument3.FilePath); + Assert.Same(newConfigDocumentInfo3.DocumentServiceProvider, newConfigDocument3.DocumentServiceProvider); + Assert.Equal("#new empty3", newConfigDocument3.GetTextSynchronously(CancellationToken.None).ToString()); + Assert.Same(Encoding.UTF8, newConfigText3.Encoding); + Assert.Equal(SourceHashAlgorithms.Default, newConfigText3.ChecksumAlgorithm); + } + + [Fact] + public void WithProjectInfo_Unsupported_RemovingCompilationOptions() + { + var projectId = ProjectId.CreateNewId(); + + using var workspace = CreateWorkspace(); + + var solution = workspace.CurrentSolution + .AddProject(ProjectInfo.Create(projectId, VersionStamp.Default, "proj1", "proj1", LanguageNames.CSharp, Path.Combine(s_projectDir, "proj1.dll"))); + + var oldProject = solution.GetRequiredProject(projectId); + var documentIds = oldProject.DocumentIds; + + var newInfo = ProjectInfo.Create( + projectId, + VersionStamp.Create(), + name: "newProjectName", + assemblyName: "newAssemblyName", + language: LanguageNames.CSharp, + filePath: "newFilePath.cs", + outputFilePath: "newOutputFilePath", + outputRefFilePath: "newOutputRef", + compilationOptions: new CSharpCompilationOptions(OutputKind.WindowsApplication, moduleName: "newModuleName"), + parseOptions: null, + documents: [], + additionalDocuments: [], + projectReferences: [], + metadataReferences: [], + analyzerReferences: [], + isSubmission: false, + hostObjectType: null); + + Assert.Throws(() => solution.WithProjectInfo(newInfo)); + } + + [Fact] + public void WithProjectInfo_Unsupported_RemovingParseOptions() + { + var projectId = ProjectId.CreateNewId(); + + using var workspace = CreateWorkspace(); + + var solution = workspace.CurrentSolution + .AddProject(ProjectInfo.Create(projectId, VersionStamp.Default, "proj1", "proj1", LanguageNames.CSharp, Path.Combine(s_projectDir, "proj1.dll"))); + + var oldProject = solution.GetRequiredProject(projectId); + var documentIds = oldProject.DocumentIds; + + var newInfo = ProjectInfo.Create( + projectId, + VersionStamp.Create(), + name: "newProjectName", + assemblyName: "newAssemblyName", + language: LanguageNames.CSharp, + filePath: "newFilePath.cs", + outputFilePath: "newOutputFilePath", + outputRefFilePath: "newOutputRef", + compilationOptions: null, + parseOptions: new CSharpParseOptions(CS.LanguageVersion.CSharp5), + documents: [], + additionalDocuments: [], + projectReferences: [], + metadataReferences: [], + analyzerReferences: [], + isSubmission: false, + hostObjectType: null); + + Assert.Throws(() => solution.WithProjectInfo(newInfo)); + } + + [Fact] + public void WithProjectInfo_Unsupported_ChangingLanguage() + { + var projectId = ProjectId.CreateNewId(); + + using var workspace = CreateWorkspace(); + + var solution = workspace.CurrentSolution + .AddProject(ProjectInfo.Create(projectId, VersionStamp.Default, "proj1", "proj1", LanguageNames.CSharp, Path.Combine(s_projectDir, "proj1.dll"))); + + var oldProject = solution.GetRequiredProject(projectId); + var documentIds = oldProject.DocumentIds; + + var newInfo = ProjectInfo.Create( + projectId, + VersionStamp.Create(), + name: "newProjectName", + assemblyName: "newAssemblyName", + language: LanguageNames.VisualBasic, + filePath: "newFilePath.cs", + outputFilePath: "newOutputFilePath", + outputRefFilePath: "newOutputRef", + compilationOptions: null, + parseOptions: null, + documents: [], + additionalDocuments: [], + projectReferences: [], + metadataReferences: [], + analyzerReferences: [], + isSubmission: false, + hostObjectType: null); + + Assert.Throws(() => solution.WithProjectInfo(newInfo)); + } + + [Fact] + public void WithProjectInfo_Unsupported_ChangingIsSubmission() + { + var projectId = ProjectId.CreateNewId(); + + using var workspace = CreateWorkspace(); + + var solution = workspace.CurrentSolution + .AddProject(ProjectInfo.Create(projectId, VersionStamp.Default, "proj1", "proj1", LanguageNames.CSharp, Path.Combine(s_projectDir, "proj1.dll"))); + + var oldProject = solution.GetRequiredProject(projectId); + var documentIds = oldProject.DocumentIds; + + var newInfo = ProjectInfo.Create( + projectId, + VersionStamp.Create(), + name: "newProjectName", + assemblyName: "newAssemblyName", + language: LanguageNames.CSharp, + filePath: "newFilePath.cs", + outputFilePath: "newOutputFilePath", + outputRefFilePath: "newOutputRef", + compilationOptions: new CSharpCompilationOptions(OutputKind.WindowsApplication, moduleName: "newModuleName"), + parseOptions: CS.CSharpParseOptions.Default, + documents: [], + additionalDocuments: [], + projectReferences: [], + metadataReferences: [], + analyzerReferences: [], + isSubmission: true, + hostObjectType: null); + + Assert.Throws(() => solution.WithProjectInfo(newInfo)); + } + [Fact] public void WithProjectAssemblyName() { @@ -1105,6 +1482,7 @@ public async Task WithProjectChecksumAlgorithm_DocumentUpdates() fileD.WriteAllBytes(bytes); var sha256 = SHA256.Create(); + // CodeQL [SM02196] This is not enabled by default but exists as a compat option for existing builds. var sha1 = SHA1.Create(); var checksumSHA1 = sha1.ComputeHash(bytes); var checksumSHA256 = sha256.ComputeHash(bytes); @@ -1222,6 +1600,7 @@ public void WithProjectCompilationOptionsExceptionHandling() var options = new CSharpCompilationOptions(OutputKind.NetModule); Assert.Throws("projectId", () => solution.WithProjectCompilationOptions(null!, options)); + Assert.Throws("options", () => solution.WithProjectCompilationOptions(projectId, options: null!)); Assert.Throws(() => solution.WithProjectCompilationOptions(ProjectId.CreateNewId(), options)); } @@ -1270,6 +1649,7 @@ public void WithProjectParseOptions() defaultThrows: true); Assert.Throws("projectId", () => solution.WithProjectParseOptions(null!, options)); + Assert.Throws("options", () => solution.WithProjectParseOptions(projectId, options: null!)); Assert.Throws(() => solution.WithProjectParseOptions(ProjectId.CreateNewId(), options)); } @@ -1329,8 +1709,8 @@ public async Task ChangingPreprocessorDirectivesMayReparse(string source, bool e Assert.Equal(document.Project.ParseOptions, oldTree.Options); ParseOptions newOptions = languageName == LanguageNames.CSharp - ? new CSharpParseOptions(preprocessorSymbols: new[] { "DEBUG" }) - : new VisualBasicParseOptions(preprocessorSymbols: new KeyValuePair[] { new("DEBUG", null) }); + ? new CSharpParseOptions(preprocessorSymbols: ["DEBUG"]) + : new VisualBasicParseOptions(preprocessorSymbols: [new("DEBUG", null)]); document = document.Project.WithParseOptions(newOptions).GetRequiredDocument(documentId); @@ -1476,12 +1856,12 @@ public void AddProjectReferences() var e = OnceEnumerable(projectRef2, externalProjectRef); var solution3 = solution.AddProjectReferences(projectId, e); - AssertEx.Equal(new[] { projectRef2 }, solution3.GetProject(projectId)!.ProjectReferences); - AssertEx.Equal(new[] { projectRef2, externalProjectRef }, solution3.GetProject(projectId)!.AllProjectReferences); + AssertEx.Equal([projectRef2], solution3.GetProject(projectId)!.ProjectReferences); + AssertEx.Equal([projectRef2, externalProjectRef], solution3.GetProject(projectId)!.AllProjectReferences); Assert.Throws("projectId", () => solution.AddProjectReferences(null!, [projectRef2])); Assert.Throws("projectReferences", () => solution.AddProjectReferences(projectId, null!)); - Assert.Throws("projectReferences[0]", () => solution.AddProjectReferences(projectId, new ProjectReference[] { null! })); + Assert.Throws("projectReferences[0]", () => solution.AddProjectReferences(projectId, [null!])); Assert.Throws("projectReferences[1]", () => solution.AddProjectReferences(projectId, [projectRef2, projectRef2])); Assert.Throws("projectReferences[1]", () => solution.AddProjectReferences(projectId, [new ProjectReference(projectId2), new ProjectReference(projectId2)])); @@ -1509,11 +1889,11 @@ public void RemoveProjectReference() // remove reference to a project that's not part of the solution: var solution2 = solution.RemoveProjectReference(projectId, externalProjectRef); - AssertEx.Equal(new[] { projectRef2 }, solution2.GetProject(projectId)!.AllProjectReferences); + AssertEx.Equal([projectRef2], solution2.GetProject(projectId)!.AllProjectReferences); // remove reference to a project that's part of the solution: var solution3 = solution.RemoveProjectReference(projectId, projectRef2); - AssertEx.Equal(new[] { externalProjectRef }, solution3.GetProject(projectId)!.AllProjectReferences); + AssertEx.Equal([externalProjectRef], solution3.GetProject(projectId)!.AllProjectReferences); var solution4 = solution3.RemoveProjectReference(projectId, externalProjectRef); Assert.Empty(solution4.GetProject(projectId)!.AllProjectReferences); @@ -1596,15 +1976,15 @@ public void AddMetadataReferences() var metadataRef2 = new TestMetadataReference(); var solution3 = solution.AddMetadataReferences(projectId, OnceEnumerable(metadataRef1, metadataRef2)); - AssertEx.Equal(new[] { metadataRef1, metadataRef2 }, solution3.GetProject(projectId)!.MetadataReferences); + AssertEx.Equal([metadataRef1, metadataRef2], solution3.GetProject(projectId)!.MetadataReferences); - Assert.Throws("projectId", () => solution.AddMetadataReferences(null!, new[] { metadataRef1 })); + Assert.Throws("projectId", () => solution.AddMetadataReferences(null!, [metadataRef1])); Assert.Throws("metadataReferences", () => solution.AddMetadataReferences(projectId, null!)); - Assert.Throws("metadataReferences[0]", () => solution.AddMetadataReferences(projectId, new MetadataReference[] { null! })); - Assert.Throws("metadataReferences[1]", () => solution.AddMetadataReferences(projectId, new[] { metadataRef1, metadataRef1 })); + Assert.Throws("metadataReferences[0]", () => solution.AddMetadataReferences(projectId, [null!])); + Assert.Throws("metadataReferences[1]", () => solution.AddMetadataReferences(projectId, [metadataRef1, metadataRef1])); // dup: - Assert.Throws(() => solution3.AddMetadataReferences(projectId, new[] { metadataRef1 })); + Assert.Throws(() => solution3.AddMetadataReferences(projectId, [metadataRef1])); } [Fact] @@ -1616,10 +1996,10 @@ public void RemoveMetadataReference() var metadataRef1 = new TestMetadataReference(); var metadataRef2 = new TestMetadataReference(); - solution = solution.WithProjectMetadataReferences(projectId, new[] { metadataRef1, metadataRef2 }); + solution = solution.WithProjectMetadataReferences(projectId, [metadataRef1, metadataRef2]); var solution2 = solution.RemoveMetadataReference(projectId, metadataRef1); - AssertEx.Equal(new[] { metadataRef2 }, solution2.GetProject(projectId)!.MetadataReferences); + AssertEx.Equal([metadataRef2], solution2.GetProject(projectId)!.MetadataReferences); var solution3 = solution2.RemoveMetadataReference(projectId, metadataRef2); Assert.Empty(solution3.GetProject(projectId)!.MetadataReferences); @@ -1666,18 +2046,18 @@ public void AddAnalyzerReferences_Project() var analyzerRef2 = new TestAnalyzerReference(); var solution3 = solution.AddAnalyzerReferences(projectId, OnceEnumerable(analyzerRef1, analyzerRef2)); - AssertEx.Equal(new[] { analyzerRef1, analyzerRef2 }, solution3.GetProject(projectId)!.AnalyzerReferences); + AssertEx.Equal([analyzerRef1, analyzerRef2], solution3.GetProject(projectId)!.AnalyzerReferences); - var solution4 = solution3.AddAnalyzerReferences(projectId, new AnalyzerReference[0]); + var solution4 = solution3.AddAnalyzerReferences(projectId, []); Assert.Same(solution, solution2); - Assert.Throws("projectId", () => solution.AddAnalyzerReferences(null!, new[] { analyzerRef1 })); + Assert.Throws("projectId", () => solution.AddAnalyzerReferences(null!, [analyzerRef1])); Assert.Throws("analyzerReferences", () => solution.AddAnalyzerReferences(projectId, null!)); - Assert.Throws("analyzerReferences[0]", () => solution.AddAnalyzerReferences(projectId, new AnalyzerReference[] { null! })); - Assert.Throws("analyzerReferences[1]", () => solution.AddAnalyzerReferences(projectId, new[] { analyzerRef1, analyzerRef1 })); + Assert.Throws("analyzerReferences[0]", () => solution.AddAnalyzerReferences(projectId, [null!])); + Assert.Throws("analyzerReferences[1]", () => solution.AddAnalyzerReferences(projectId, [analyzerRef1, analyzerRef1])); // dup: - Assert.Throws(() => solution3.AddAnalyzerReferences(projectId, new[] { analyzerRef1 })); + Assert.Throws(() => solution3.AddAnalyzerReferences(projectId, [analyzerRef1])); } [Fact] @@ -1689,10 +2069,10 @@ public void RemoveAnalyzerReference_Project() var analyzerRef1 = new TestAnalyzerReference(); var analyzerRef2 = new TestAnalyzerReference(); - solution = solution.WithProjectAnalyzerReferences(projectId, new[] { analyzerRef1, analyzerRef2 }); + solution = solution.WithProjectAnalyzerReferences(projectId, [analyzerRef1, analyzerRef2]); var solution2 = solution.RemoveAnalyzerReference(projectId, analyzerRef1); - AssertEx.Equal(new[] { analyzerRef2 }, solution2.GetProject(projectId)!.AnalyzerReferences); + AssertEx.Equal([analyzerRef2], solution2.GetProject(projectId)!.AnalyzerReferences); var solution3 = solution2.RemoveAnalyzerReference(projectId, analyzerRef2); Assert.Empty(solution3.GetProject(projectId)!.AnalyzerReferences); @@ -1734,17 +2114,17 @@ public void AddAnalyzerReferences() var analyzerRef2 = new TestAnalyzerReference(); var solution3 = solution.AddAnalyzerReferences(OnceEnumerable(analyzerRef1, analyzerRef2)); - AssertEx.Equal(new[] { analyzerRef1, analyzerRef2 }, solution3.AnalyzerReferences); + AssertEx.Equal([analyzerRef1, analyzerRef2], solution3.AnalyzerReferences); - var solution4 = solution3.AddAnalyzerReferences(new AnalyzerReference[0]); + var solution4 = solution3.AddAnalyzerReferences([]); Assert.Same(solution, solution2); Assert.Throws("analyzerReferences", () => solution.AddAnalyzerReferences(null!)); - Assert.Throws("analyzerReferences[0]", () => solution.AddAnalyzerReferences(new AnalyzerReference[] { null! })); - Assert.Throws("analyzerReferences[1]", () => solution.AddAnalyzerReferences(new[] { analyzerRef1, analyzerRef1 })); + Assert.Throws("analyzerReferences[0]", () => solution.AddAnalyzerReferences([null!])); + Assert.Throws("analyzerReferences[1]", () => solution.AddAnalyzerReferences([analyzerRef1, analyzerRef1])); // dup: - Assert.Throws(() => solution3.AddAnalyzerReferences(new[] { analyzerRef1 })); + Assert.Throws(() => solution3.AddAnalyzerReferences([analyzerRef1])); } [Fact] @@ -1755,10 +2135,10 @@ public void RemoveAnalyzerReference() var analyzerRef1 = new TestAnalyzerReference(); var analyzerRef2 = new TestAnalyzerReference(); - solution = solution.WithAnalyzerReferences(new[] { analyzerRef1, analyzerRef2 }); + solution = solution.WithAnalyzerReferences([analyzerRef1, analyzerRef2]); var solution2 = solution.RemoveAnalyzerReference(analyzerRef1); - AssertEx.Equal(new[] { analyzerRef2 }, solution2.AnalyzerReferences); + AssertEx.Equal([analyzerRef2], solution2.AnalyzerReferences); var solution3 = solution2.RemoveAnalyzerReference(analyzerRef2); Assert.Empty(solution3.AnalyzerReferences); @@ -2415,7 +2795,7 @@ public async Task TestProjectDependencyLoadingAsync() [Fact] public async Task TestAddMetadataReferencesAsync() { - var mefReference = TestMetadata.Net451.SystemCore; + var mefReference = NetFramework.SystemCore; using var workspace = CreateWorkspace(); var solution = workspace.CurrentSolution; var project1 = ProjectId.CreateNewId(); @@ -4071,7 +4451,7 @@ ImmutableArray GetSyntaxTrees() var oldVersion = GetVersion(); - solution = solution.WithProjectDocumentsOrder(pid, ImmutableList.CreateRange(new[] { did5, did4, did3, did2, did1 })); + solution = solution.WithProjectDocumentsOrder(pid, ImmutableList.CreateRange([did5, did4, did3, did2, did1])); var newVersion = GetVersion(); @@ -4096,7 +4476,7 @@ ImmutableArray GetSyntaxTrees() Assert.Equal("test2.cs", syntaxTrees[3].FilePath, StringComparer.OrdinalIgnoreCase); Assert.Equal("test1.cs", syntaxTrees[4].FilePath, StringComparer.OrdinalIgnoreCase); - solution = solution.WithProjectDocumentsOrder(pid, ImmutableList.CreateRange(new[] { did5, did4, did3, did2, did1 })); + solution = solution.WithProjectDocumentsOrder(pid, ImmutableList.CreateRange([did5, did4, did3, did2, did1])); var newSameVersion = GetVersion(); @@ -4137,8 +4517,8 @@ public void TestUpdateDocumentsOrderExceptions() Assert.Throws(() => solution = solution.WithProjectDocumentsOrder(pid, ImmutableList.Create())); Assert.Throws(() => solution = solution.WithProjectDocumentsOrder(pid, null)); - Assert.Throws(() => solution = solution.WithProjectDocumentsOrder(pid, ImmutableList.CreateRange(new[] { did5, did3, did2, did1 }))); - Assert.Throws(() => solution = solution.WithProjectDocumentsOrder(pid, ImmutableList.CreateRange(new[] { did3, did2, did1 }))); + Assert.Throws(() => solution = solution.WithProjectDocumentsOrder(pid, ImmutableList.CreateRange([did5, did3, did2, did1]))); + Assert.Throws(() => solution = solution.WithProjectDocumentsOrder(pid, ImmutableList.CreateRange([did3, did2, did1]))); } [Theory, CombinatorialData] @@ -4304,7 +4684,7 @@ public async Task TestAddingEditorConfigFileWithIsGeneratedCodeOption() var sourceDocumentId = DocumentId.CreateNewId(projectId); solution = solution.AddProject(projectId, "Test", "Test.dll", LanguageNames.CSharp) - .WithProjectMetadataReferences(projectId, new[] { TestMetadata.Net451.mscorlib }) + .WithProjectMetadataReferences(projectId, [NetFramework.mscorlib]) .WithProjectCompilationOptions(projectId, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Enable)); var src = @" class C @@ -4367,6 +4747,26 @@ public void NoCompilationProjectsHaveNullSyntaxTreesAndSemanticModels() Assert.Null(document.GetSemanticModelAsync().Result); } + [Fact] + public void NoCompilation_SourceCodeKind() + { + using var workspace = CreateWorkspace([typeof(NoCompilationLanguageService)]); + var projectId = ProjectId.CreateNewId(); + var documentId = DocumentId.CreateNewId(projectId); + + var solution = workspace.CurrentSolution + .AddProject(projectId, "Test", "Test.dll", NoCompilationConstants.LanguageName) + .AddDocument(DocumentInfo.Create(documentId, "Test", sourceCodeKind: SourceCodeKind.Script)); + + var document1 = solution.GetRequiredDocument(documentId); + Assert.Equal(SourceCodeKind.Script, document1.SourceCodeKind); + Assert.Null(document1.DocumentState.ParseOptions); + + var document2 = document1.WithSourceCodeKind(SourceCodeKind.Regular); + Assert.Equal(SourceCodeKind.Regular, document2.SourceCodeKind); + Assert.Null(document2.DocumentState.ParseOptions); + } + [Fact] public void ChangingFilePathOfFileInNoCompilationProjectWorks() { diff --git a/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs b/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs index bb8a74e919e5a..b686a59887b39 100644 --- a/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs +++ b/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs @@ -21,868 +21,907 @@ using static Microsoft.CodeAnalysis.UnitTests.SolutionUtilities; using static Microsoft.CodeAnalysis.UnitTests.WorkspaceTestUtilities; -namespace Microsoft.CodeAnalysis.UnitTests +namespace Microsoft.CodeAnalysis.UnitTests; + +[UseExportProvider] +public sealed class SolutionWithSourceGeneratorTests : TestBase { - [UseExportProvider] - public sealed class SolutionWithSourceGeneratorTests : TestBase + [Theory, CombinatorialData] + public async Task SourceGeneratorBasedOnAdditionalFileGeneratesSyntaxTrees( + bool fetchCompilationBeforeAddingAdditionalFile, TestHost testHost) { - [Theory, CombinatorialData] - public async Task SourceGeneratorBasedOnAdditionalFileGeneratesSyntaxTrees( - bool fetchCompilationBeforeAddingAdditionalFile, TestHost testHost) - { - // This test is just the sanity test to make sure generators work at all. There's not a special scenario being - // tested. + // This test is just the sanity test to make sure generators work at all. There's not a special scenario being + // tested. - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference); + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference); - // Optionally fetch the compilation first, which validates that we handle both running the generator - // when the file already exists, and when it is added incrementally. - Compilation? originalCompilation = null; + // Optionally fetch the compilation first, which validates that we handle both running the generator + // when the file already exists, and when it is added incrementally. + Compilation? originalCompilation = null; - if (fetchCompilationBeforeAddingAdditionalFile) - { - originalCompilation = await project.GetRequiredCompilationAsync(CancellationToken.None); - } + if (fetchCompilationBeforeAddingAdditionalFile) + { + originalCompilation = await project.GetRequiredCompilationAsync(CancellationToken.None); + } - project = project.AddAdditionalDocument("Test.txt", "Hello, world!").Project; + project = project.AddAdditionalDocument("Test.txt", "Hello, world!").Project; - var newCompilation = await project.GetRequiredCompilationAsync(CancellationToken.None); + var newCompilation = await project.GetRequiredCompilationAsync(CancellationToken.None); - Assert.NotSame(originalCompilation, newCompilation); - var generatedTree = Assert.Single(newCompilation.SyntaxTrees); - var generatorType = typeof(GenerateFileForEachAdditionalFileWithContentsCommented); + Assert.NotSame(originalCompilation, newCompilation); + var generatedTree = Assert.Single(newCompilation.SyntaxTrees); + var generatorType = typeof(GenerateFileForEachAdditionalFileWithContentsCommented); - Assert.Equal($"{generatorType.Assembly.GetName().Name}\\{generatorType.FullName}\\Test.generated.cs", generatedTree.FilePath); + Assert.Equal($"{generatorType.Assembly.GetName().Name}\\{generatorType.FullName}\\Test.generated.cs", generatedTree.FilePath); - var generatedDocument = Assert.Single(await project.GetSourceGeneratedDocumentsAsync()); - Assert.Same(generatedTree, await generatedDocument.GetSyntaxTreeAsync()); - } + var generatedDocument = Assert.Single(await project.GetSourceGeneratedDocumentsAsync()); + Assert.Same(generatedTree, await generatedDocument.GetSyntaxTreeAsync()); + } - [Theory, CombinatorialData, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1655835")] - public async Task WithReferencesMethodCorrectlyUpdatesWithEqualReferences(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); + [Theory, CombinatorialData, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1655835")] + public async Task WithReferencesMethodCorrectlyUpdatesWithEqualReferences(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); - // AnalyzerReferences may implement equality (AnalyezrFileReference does), and we want to make sure if we substitute out one - // reference with another reference that's equal, we correctly update generators. We'll have the underlying generators - // be different since two AnalyzerFileReferences that are value equal but different instances would have their own generators as well. - const string SharedPath = "Z:\\Generator.dll"; - static ISourceGenerator CreateGenerator() => new SingleFileTestGenerator("// StaticContent", hintName: "generated"); + // AnalyzerReferences may implement equality (AnalyezrFileReference does), and we want to make sure if we substitute out one + // reference with another reference that's equal, we correctly update generators. We'll have the underlying generators + // be different since two AnalyzerFileReferences that are value equal but different instances would have their own generators as well. + const string SharedPath = "Z:\\Generator.dll"; + static ISourceGenerator CreateGenerator() => new SingleFileTestGenerator("// StaticContent", hintName: "generated"); - var analyzerReference1 = new TestGeneratorReferenceWithFilePathEquality(CreateGenerator(), SharedPath); - var analyzerReference2 = new TestGeneratorReferenceWithFilePathEquality(CreateGenerator(), SharedPath); + var analyzerReference1 = new TestGeneratorReferenceWithFilePathEquality(CreateGenerator(), SharedPath); + var analyzerReference2 = new TestGeneratorReferenceWithFilePathEquality(CreateGenerator(), SharedPath); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference1); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference1); - Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); + Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); - // Go from one analyzer reference to the other - project = project.WithAnalyzerReferences(new[] { analyzerReference2 }); + // Go from one analyzer reference to the other + project = project.WithAnalyzerReferences([analyzerReference2]); - Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); + Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); - // Now remove and confirm that we don't have any files - project = project.WithAnalyzerReferences([]); + // Now remove and confirm that we don't have any files + project = project.WithAnalyzerReferences([]); - Assert.Empty((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); - } + Assert.Empty((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); + } - private class TestGeneratorReferenceWithFilePathEquality : TestGeneratorReference, IEquatable + private class TestGeneratorReferenceWithFilePathEquality : TestGeneratorReference, IEquatable + { + public TestGeneratorReferenceWithFilePathEquality(ISourceGenerator generator, string analyzerFilePath) + : base(generator, analyzerFilePath) { - public TestGeneratorReferenceWithFilePathEquality(ISourceGenerator generator, string analyzerFilePath) - : base(generator, analyzerFilePath) - { - } + } - public override bool Equals(object? obj) => Equals(obj as AnalyzerReference); - public override string FullPath => base.FullPath!; // This derived class always has this non-null - public override int GetHashCode() => this.FullPath.GetHashCode(); + public override bool Equals(object? obj) => Equals(obj as AnalyzerReference); + public override string FullPath => base.FullPath!; // This derived class always has this non-null + public override int GetHashCode() => this.FullPath.GetHashCode(); - public bool Equals(AnalyzerReference? other) - { - return other is TestGeneratorReferenceWithFilePathEquality otherReference && - this.FullPath == otherReference.FullPath; - } + public bool Equals(AnalyzerReference? other) + { + return other is TestGeneratorReferenceWithFilePathEquality otherReference && + this.FullPath == otherReference.FullPath; } + } - [Theory, CombinatorialData] - public async Task WithReferencesMethodCorrectlyAddsAndRemovesRunningGenerators(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); + [Theory, CombinatorialData] + public async Task WithReferencesMethodCorrectlyAddsAndRemovesRunningGenerators(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); - // We always have a single generator in this test, and we add or remove a second one. This is critical - // to ensuring we correctly update our existing GeneratorDriver we may have from a prior run with the new - // generators passed to WithAnalyzerReferences. If we only swap from zero generators to one generator, - // we don't have a prior GeneratorDriver to update, since we don't make a GeneratorDriver if we have no generators. - // Similarly, once we go from one back to zero, we end up getting rid of our GeneratorDriver entirely since - // we have no need for it, as an optimization. - var generatorReferenceToKeep = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent", hintName: "generatorReferenceToKeep")); - var analyzerReferenceToAddAndRemove = new TestGeneratorReference(new SingleFileTestGenerator2("// More Static Content", hintName: "analyzerReferenceToAddAndRemove")); + // We always have a single generator in this test, and we add or remove a second one. This is critical + // to ensuring we correctly update our existing GeneratorDriver we may have from a prior run with the new + // generators passed to WithAnalyzerReferences. If we only swap from zero generators to one generator, + // we don't have a prior GeneratorDriver to update, since we don't make a GeneratorDriver if we have no generators. + // Similarly, once we go from one back to zero, we end up getting rid of our GeneratorDriver entirely since + // we have no need for it, as an optimization. + var generatorReferenceToKeep = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent", hintName: "generatorReferenceToKeep")); + var analyzerReferenceToAddAndRemove = new TestGeneratorReference(new SingleFileTestGenerator2("// More Static Content", hintName: "analyzerReferenceToAddAndRemove")); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(generatorReferenceToKeep); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(generatorReferenceToKeep); - Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); + Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); - // Go from one generator to two. - project = project.WithAnalyzerReferences(new[] { generatorReferenceToKeep, analyzerReferenceToAddAndRemove }); + // Go from one generator to two. + project = project.WithAnalyzerReferences([generatorReferenceToKeep, analyzerReferenceToAddAndRemove]); - Assert.Equal(2, (await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees.Count()); + Assert.Equal(2, (await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees.Count()); - // And go back to one - project = project.WithAnalyzerReferences(new[] { generatorReferenceToKeep }); + // And go back to one + project = project.WithAnalyzerReferences([generatorReferenceToKeep]); - Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); - } + Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); + } - // We only run this test on Release, as the compiler has asserts that trigger in Debug that the type names probably shouldn't be the same. - [ConditionalTheory(typeof(IsRelease)), CombinatorialData] - public async Task GeneratorAddedWithDifferentFilePathsProducesDistinctDocumentIds(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); + // We only run this test on Release, as the compiler has asserts that trigger in Debug that the type names probably shouldn't be the same. + [ConditionalTheory(typeof(IsRelease)), CombinatorialData] + public async Task GeneratorAddedWithDifferentFilePathsProducesDistinctDocumentIds(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); - // Produce two generator references with different paths, but the same generator by assembly/type. We will still give them separate - // generator instances, because in the "real" analyzer reference case each analyzer reference produces it's own generator objects. - var generatorReference1 = new TestGeneratorReference(new SingleFileTestGenerator("", hintName: "DuplicateFile"), analyzerFilePath: "Z:\\A.dll"); - var generatorReference2 = new TestGeneratorReference(new SingleFileTestGenerator("", hintName: "DuplicateFile"), analyzerFilePath: "Z:\\B.dll"); + // Produce two generator references with different paths, but the same generator by assembly/type. We will still give them separate + // generator instances, because in the "real" analyzer reference case each analyzer reference produces it's own generator objects. + var generatorReference1 = new TestGeneratorReference(new SingleFileTestGenerator("", hintName: "DuplicateFile"), analyzerFilePath: "Z:\\A.dll"); + var generatorReference2 = new TestGeneratorReference(new SingleFileTestGenerator("", hintName: "DuplicateFile"), analyzerFilePath: "Z:\\B.dll"); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReferences(new[] { generatorReference1, generatorReference2 }); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReferences([generatorReference1, generatorReference2]); - Assert.Equal(2, (await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees.Count()); + Assert.Equal(2, (await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees.Count()); - var generatedDocuments = (await project.GetSourceGeneratedDocumentsAsync()).ToList(); - Assert.Equal(2, generatedDocuments.Count); + var generatedDocuments = (await project.GetSourceGeneratedDocumentsAsync()).ToList(); + Assert.Equal(2, generatedDocuments.Count); - Assert.NotEqual(generatedDocuments[0].Id, generatedDocuments[1].Id); - } + Assert.NotEqual(generatedDocuments[0].Id, generatedDocuments[1].Id); + } - [Fact] - public async Task IncrementalSourceGeneratorInvokedCorrectNumberOfTimes() - { - using var workspace = CreateWorkspace([typeof(TestCSharpCompilationFactoryServiceWithIncrementalGeneratorTracking)]); - var generator = new GenerateFileForEachAdditionalFileWithContentsCommented(); - var analyzerReference = new TestGeneratorReference(generator); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddAdditionalDocument("Test.txt", "Hello, world!").Project - .AddAdditionalDocument("Test2.txt", "Hello, world!").Project; + [Fact] + public async Task IncrementalSourceGeneratorInvokedCorrectNumberOfTimes() + { + using var workspace = CreateWorkspace([typeof(TestCSharpCompilationFactoryServiceWithIncrementalGeneratorTracking)]); + var generator = new GenerateFileForEachAdditionalFileWithContentsCommented(); + var analyzerReference = new TestGeneratorReference(generator); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddAdditionalDocument("Test.txt", "Hello, world!").Project + .AddAdditionalDocument("Test2.txt", "Hello, world!").Project; - var compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); + var compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); - var generatorDriver = project.Solution.CompilationState.GetTestAccessor().GetGeneratorDriver(project)!; - - var runResult = generatorDriver!.GetRunResult().Results[0]; - - Assert.Equal(2, compilation.SyntaxTrees.Count()); - Assert.Equal(2, runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName].Length); - Assert.All(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], - step => - { - Assert.Collection(step.Inputs, - source => Assert.Equal(IncrementalStepRunReason.New, source.Source.Outputs[source.OutputIndex].Reason)); - Assert.Collection(step.Outputs, - output => Assert.Equal(IncrementalStepRunReason.New, output.Reason)); - }); - - // Change one of the additional documents, and rerun; we should only reprocess that one change, since this - // is an incremental generator. - project = project.AdditionalDocuments.First().WithAdditionalDocumentText(SourceText.From("Changed text!")).Project; - - compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); - generatorDriver = project.Solution.CompilationState.GetTestAccessor().GetGeneratorDriver(project)!; - runResult = generatorDriver.GetRunResult().Results[0]; - - Assert.Equal(2, compilation.SyntaxTrees.Count()); - Assert.Equal(2, runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName].Length); - Assert.Contains(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], - step => - { - return step.Inputs.Length == 1 - && step.Inputs[0].Source.Outputs[step.Inputs[0].OutputIndex].Reason == IncrementalStepRunReason.Modified - && step.Outputs is [{ Reason: IncrementalStepRunReason.Modified }]; - }); - Assert.Contains(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], - step => - { - return step.Inputs.Length == 1 - && step.Inputs[0].Source.Outputs[step.Inputs[0].OutputIndex].Reason == IncrementalStepRunReason.Cached - && step.Outputs is [{ Reason: IncrementalStepRunReason.Cached }]; - }); - - // Change one of the source documents, and rerun; we should again only reprocess that one change. - project = project.AddDocument("Source.cs", SourceText.From("")).Project; - - compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); - generatorDriver = project.Solution.CompilationState.GetTestAccessor().GetGeneratorDriver(project)!; - runResult = generatorDriver.GetRunResult().Results[0]; - - // We have one extra syntax tree now, but it did not require any invocations of the incremental generator. - Assert.Equal(3, compilation.SyntaxTrees.Count()); - Assert.Equal(2, runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName].Length); - Assert.All(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], - step => - { - Assert.Collection(step.Inputs, - source => Assert.Equal(IncrementalStepRunReason.Cached, source.Source.Outputs[source.OutputIndex].Reason)); - Assert.Collection(step.Outputs, - output => Assert.Equal(IncrementalStepRunReason.Cached, output.Reason)); - }); - } + var generatorDriver = project.Solution.CompilationState.GetTestAccessor().GetGeneratorDriver(project)!; - [Theory, CombinatorialData] - public async Task SourceGeneratorContentStillIncludedAfterSourceFileChange(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddDocument("Hello.cs", "// Source File").Project - .AddAdditionalDocument("Test.txt", "Hello, world!").Project; + var runResult = generatorDriver!.GetRunResult().Results[0]; - var documentId = project.DocumentIds.Single(); + Assert.Equal(2, compilation.SyntaxTrees.Count()); + Assert.Equal(2, runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName].Length); + Assert.All(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], + step => + { + Assert.Collection(step.Inputs, + source => Assert.Equal(IncrementalStepRunReason.New, source.Source.Outputs[source.OutputIndex].Reason)); + Assert.Collection(step.Outputs, + output => Assert.Equal(IncrementalStepRunReason.New, output.Reason)); + }); + + // Change one of the additional documents, and rerun; we should only reprocess that one change, since this + // is an incremental generator. + project = project.AdditionalDocuments.First().WithAdditionalDocumentText(SourceText.From("Changed text!")).Project; + + compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); + generatorDriver = project.Solution.CompilationState.GetTestAccessor().GetGeneratorDriver(project)!; + runResult = generatorDriver.GetRunResult().Results[0]; + + Assert.Equal(2, compilation.SyntaxTrees.Count()); + Assert.Equal(2, runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName].Length); + Assert.Contains(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], + step => + { + return step.Inputs.Length == 1 + && step.Inputs[0].Source.Outputs[step.Inputs[0].OutputIndex].Reason == IncrementalStepRunReason.Modified + && step.Outputs is [{ Reason: IncrementalStepRunReason.Modified }]; + }); + Assert.Contains(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], + step => + { + return step.Inputs.Length == 1 + && step.Inputs[0].Source.Outputs[step.Inputs[0].OutputIndex].Reason == IncrementalStepRunReason.Cached + && step.Outputs is [{ Reason: IncrementalStepRunReason.Cached }]; + }); + + // Change one of the source documents, and rerun; we should again only reprocess that one change. + project = project.AddDocument("Source.cs", SourceText.From("")).Project; + + compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); + generatorDriver = project.Solution.CompilationState.GetTestAccessor().GetGeneratorDriver(project)!; + runResult = generatorDriver.GetRunResult().Results[0]; + + // We have one extra syntax tree now, but it did not require any invocations of the incremental generator. + Assert.Equal(3, compilation.SyntaxTrees.Count()); + Assert.Equal(2, runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName].Length); + Assert.All(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], + step => + { + Assert.Collection(step.Inputs, + source => Assert.Equal(IncrementalStepRunReason.Cached, source.Source.Outputs[source.OutputIndex].Reason)); + Assert.Collection(step.Outputs, + output => Assert.Equal(IncrementalStepRunReason.Cached, output.Reason)); + }); + } - await AssertCompilationContainsOneRegularAndOneGeneratedFile(project, documentId, "// Hello, world!"); + [Theory, CombinatorialData] + public async Task SourceGeneratorContentStillIncludedAfterSourceFileChange(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddDocument("Hello.cs", "// Source File").Project + .AddAdditionalDocument("Test.txt", "Hello, world!").Project; - project = project.Solution.WithDocumentText(documentId, SourceText.From("// Changed Source File")).Projects.Single(); + var documentId = project.DocumentIds.Single(); - await AssertCompilationContainsOneRegularAndOneGeneratedFile(project, documentId, "// Hello, world!"); + await AssertCompilationContainsOneRegularAndOneGeneratedFile(project, documentId, "// Hello, world!"); - static async Task AssertCompilationContainsOneRegularAndOneGeneratedFile(Project project, DocumentId documentId, string expectedGeneratedContents) - { - var compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); + project = project.Solution.WithDocumentText(documentId, SourceText.From("// Changed Source File")).Projects.Single(); + + await AssertCompilationContainsOneRegularAndOneGeneratedFile(project, documentId, "// Hello, world!"); + + static async Task AssertCompilationContainsOneRegularAndOneGeneratedFile(Project project, DocumentId documentId, string expectedGeneratedContents) + { + var compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); - var regularDocumentSyntaxTree = await project.GetRequiredDocument(documentId).GetRequiredSyntaxTreeAsync(CancellationToken.None); - Assert.Contains(regularDocumentSyntaxTree, compilation.SyntaxTrees); + var regularDocumentSyntaxTree = await project.GetRequiredDocument(documentId).GetRequiredSyntaxTreeAsync(CancellationToken.None); + Assert.Contains(regularDocumentSyntaxTree, compilation.SyntaxTrees); - var generatedSyntaxTree = Assert.Single(compilation.SyntaxTrees.Where(t => t != regularDocumentSyntaxTree)); - Assert.IsType(project.GetDocument(generatedSyntaxTree)); + var generatedSyntaxTree = Assert.Single(compilation.SyntaxTrees.Where(t => t != regularDocumentSyntaxTree)); + Assert.IsType(project.GetDocument(generatedSyntaxTree)); - Assert.Equal(expectedGeneratedContents, generatedSyntaxTree.GetText().ToString()); - } + Assert.Equal(expectedGeneratedContents, generatedSyntaxTree.GetText().ToString()); } + } - // This will make a series of changes to additional files and assert that we correctly update generated output at various times. - // By making this a theory with a bunch of booleans, it tests that we are correctly handling the situation where we queue up multiple changes - // to the Compilation at once. - [Theory, CombinatorialData] - public async Task SourceGeneratorContentChangesAfterAdditionalFileChanges( - bool assertRightAway, - bool assertAfterAdd, - bool assertAfterFirstChange, - bool assertAfterSecondChange, - TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference); + // This will make a series of changes to additional files and assert that we correctly update generated output at various times. + // By making this a theory with a bunch of booleans, it tests that we are correctly handling the situation where we queue up multiple changes + // to the Compilation at once. + [Theory, CombinatorialData] + public async Task SourceGeneratorContentChangesAfterAdditionalFileChanges( + bool assertRightAway, + bool assertAfterAdd, + bool assertAfterFirstChange, + bool assertAfterSecondChange, + TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference); - if (assertRightAway) - await AssertCompilationContainsGeneratedFilesAsync(project, expectedGeneratedContents: []); + if (assertRightAway) + await AssertCompilationContainsGeneratedFilesAsync(project, expectedGeneratedContents: []); - project = project.AddAdditionalDocument("Test.txt", "Hello, world!").Project; - var additionalDocumentId = project.AdditionalDocumentIds.Single(); + project = project.AddAdditionalDocument("Test.txt", "Hello, world!").Project; + var additionalDocumentId = project.AdditionalDocumentIds.Single(); - if (assertAfterAdd) - await AssertCompilationContainsGeneratedFilesAsync(project, "// Hello, world!"); + if (assertAfterAdd) + await AssertCompilationContainsGeneratedFilesAsync(project, "// Hello, world!"); - project = project.Solution.WithAdditionalDocumentText(additionalDocumentId, SourceText.From("Hello, everyone!")).Projects.Single(); + project = project.Solution.WithAdditionalDocumentText(additionalDocumentId, SourceText.From("Hello, everyone!")).Projects.Single(); - if (assertAfterFirstChange) - await AssertCompilationContainsGeneratedFilesAsync(project, "// Hello, everyone!"); + if (assertAfterFirstChange) + await AssertCompilationContainsGeneratedFilesAsync(project, "// Hello, everyone!"); - project = project.Solution.WithAdditionalDocumentText(additionalDocumentId, SourceText.From("Good evening, everyone!")).Projects.Single(); + project = project.Solution.WithAdditionalDocumentText(additionalDocumentId, SourceText.From("Good evening, everyone!")).Projects.Single(); - if (assertAfterSecondChange) - await AssertCompilationContainsGeneratedFilesAsync(project, "// Good evening, everyone!"); + if (assertAfterSecondChange) + await AssertCompilationContainsGeneratedFilesAsync(project, "// Good evening, everyone!"); - project = project.RemoveAdditionalDocument(additionalDocumentId); + project = project.RemoveAdditionalDocument(additionalDocumentId); - await AssertCompilationContainsGeneratedFilesAsync(project, expectedGeneratedContents: []); + await AssertCompilationContainsGeneratedFilesAsync(project, expectedGeneratedContents: []); - static async Task AssertCompilationContainsGeneratedFilesAsync(Project project, params string[] expectedGeneratedContents) - { - var compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); + static async Task AssertCompilationContainsGeneratedFilesAsync(Project project, params string[] expectedGeneratedContents) + { + var compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); - foreach (var tree in compilation.SyntaxTrees) - Assert.IsType(project.GetDocument(tree)); + foreach (var tree in compilation.SyntaxTrees) + Assert.IsType(project.GetDocument(tree)); - var texts = compilation.SyntaxTrees.Select(t => t.GetText().ToString()); - AssertEx.SetEqual(expectedGeneratedContents, texts); - } + var texts = compilation.SyntaxTrees.Select(t => t.GetText().ToString()); + AssertEx.SetEqual(expectedGeneratedContents, texts); } + } - [Theory, CombinatorialData] - public async Task PartialCompilationsIncludeGeneratedFilesAfterFullGeneration(TestHost testHost) - { - using var workspace = CreateWorkspaceWithPartialSemantics(testHost); - var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddDocument("Hello.cs", "// Source File").Project - .AddAdditionalDocument("Test.txt", "Hello, world!").Project; + [Theory, CombinatorialData] + public async Task PartialCompilationsIncludeGeneratedFilesAfterFullGeneration(TestHost testHost) + { + using var workspace = CreateWorkspaceWithPartialSemantics(testHost); + var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddDocument("Hello.cs", "// Source File").Project + .AddAdditionalDocument("Test.txt", "Hello, world!").Project; - var fullCompilation = await project.GetRequiredCompilationAsync(CancellationToken.None); + var fullCompilation = await project.GetRequiredCompilationAsync(CancellationToken.None); - Assert.Equal(2, fullCompilation.SyntaxTrees.Count()); + Assert.Equal(2, fullCompilation.SyntaxTrees.Count()); - var partialProject = project.Documents.Single().WithFrozenPartialSemantics(CancellationToken.None).Project; - Assert.NotSame(partialProject, project); - var partialCompilation = await partialProject.GetRequiredCompilationAsync(CancellationToken.None); + var partialProject = project.Documents.Single().WithFrozenPartialSemantics(CancellationToken.None).Project; + Assert.NotSame(partialProject, project); + var partialCompilation = await partialProject.GetRequiredCompilationAsync(CancellationToken.None); - Assert.Same(fullCompilation, partialCompilation); - } + Assert.Same(fullCompilation, partialCompilation); + } - [Theory, CombinatorialData] - public async Task DocumentIdOfGeneratedDocumentsIsStable(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var projectBeforeChange = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddAdditionalDocument("Test.txt", "Hello, world!").Project; + [Theory, CombinatorialData] + public async Task DocumentIdOfGeneratedDocumentsIsStable(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); + var projectBeforeChange = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddAdditionalDocument("Test.txt", "Hello, world!").Project; - var generatedDocumentBeforeChange = Assert.Single(await projectBeforeChange.GetSourceGeneratedDocumentsAsync()); + var generatedDocumentBeforeChange = Assert.Single(await projectBeforeChange.GetSourceGeneratedDocumentsAsync()); - var projectAfterChange = - projectBeforeChange.Solution.WithAdditionalDocumentText( - projectBeforeChange.AdditionalDocumentIds.Single(), - SourceText.From("Hello, world!!!!")).Projects.Single(); + var projectAfterChange = + projectBeforeChange.Solution.WithAdditionalDocumentText( + projectBeforeChange.AdditionalDocumentIds.Single(), + SourceText.From("Hello, world!!!!")).Projects.Single(); - var generatedDocumentAfterChange = Assert.Single(await projectAfterChange.GetSourceGeneratedDocumentsAsync()); + var generatedDocumentAfterChange = Assert.Single(await projectAfterChange.GetSourceGeneratedDocumentsAsync()); - Assert.NotSame(generatedDocumentBeforeChange, generatedDocumentAfterChange); - Assert.Equal(generatedDocumentBeforeChange.Id, generatedDocumentAfterChange.Id); - } + Assert.NotSame(generatedDocumentBeforeChange, generatedDocumentAfterChange); + Assert.Equal(generatedDocumentBeforeChange.Id, generatedDocumentAfterChange.Id); + } - [Theory, CombinatorialData] - public async Task DocumentIdGuidInDifferentProjectsIsDifferent(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); + [Theory, CombinatorialData] + public async Task DocumentIdGuidInDifferentProjectsIsDifferent(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var solutionWithProjects = AddProjectWithReference(workspace.CurrentSolution, analyzerReference); - solutionWithProjects = AddProjectWithReference(solutionWithProjects, analyzerReference); + var solutionWithProjects = AddProjectWithReference(workspace.CurrentSolution, analyzerReference); + solutionWithProjects = AddProjectWithReference(solutionWithProjects, analyzerReference); - var projectIds = solutionWithProjects.ProjectIds.ToList(); + var projectIds = solutionWithProjects.ProjectIds.ToList(); - var generatedDocumentsInFirstProject = await solutionWithProjects.GetRequiredProject(projectIds[0]).GetSourceGeneratedDocumentsAsync(); - var generatedDocumentsInSecondProject = await solutionWithProjects.GetRequiredProject(projectIds[1]).GetSourceGeneratedDocumentsAsync(); + var generatedDocumentsInFirstProject = await solutionWithProjects.GetRequiredProject(projectIds[0]).GetSourceGeneratedDocumentsAsync(); + var generatedDocumentsInSecondProject = await solutionWithProjects.GetRequiredProject(projectIds[1]).GetSourceGeneratedDocumentsAsync(); - // A DocumentId consists of a GUID and then the ProjectId it's within. Even if these two documents have the same GUID, - // they'll still be not equal because of the different ProjectIds. However, we'll also assert the GUIDs should be different as well, - // because otherwise things can get confusing. If nothing else, the DocumentId debugger display string shows only the GUID, so you could - // easily confuse them as being the same. - Assert.NotEqual(generatedDocumentsInFirstProject.Single().Id.Id, generatedDocumentsInSecondProject.Single().Id.Id); + // A DocumentId consists of a GUID and then the ProjectId it's within. Even if these two documents have the same GUID, + // they'll still be not equal because of the different ProjectIds. However, we'll also assert the GUIDs should be different as well, + // because otherwise things can get confusing. If nothing else, the DocumentId debugger display string shows only the GUID, so you could + // easily confuse them as being the same. + Assert.NotEqual(generatedDocumentsInFirstProject.Single().Id.Id, generatedDocumentsInSecondProject.Single().Id.Id); - static Solution AddProjectWithReference(Solution solution, TestGeneratorReference analyzerReference) - { - var project = AddEmptyProject(solution); - project = project.AddAnalyzerReference(analyzerReference); - project = project.AddAdditionalDocument("Test.txt", "Hello, world!").Project; + static Solution AddProjectWithReference(Solution solution, TestGeneratorReference analyzerReference) + { + var project = AddEmptyProject(solution); + project = project.AddAnalyzerReference(analyzerReference); + project = project.AddAdditionalDocument("Test.txt", "Hello, world!").Project; - return project.Solution; - } + return project.Solution; } + } - [Theory, CombinatorialData] - public async Task CompilationsInCompilationReferencesIncludeGeneratedSourceFiles(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var solution = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddAdditionalDocument("Test.txt", "Hello, world!").Project.Solution; - - var projectIdWithGenerator = solution.ProjectIds.Single(); - var projectIdWithReference = ProjectId.CreateNewId(); + [Theory, CombinatorialData] + public async Task CompilationsInCompilationReferencesIncludeGeneratedSourceFiles(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); + var solution = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddAdditionalDocument("Test.txt", "Hello, world!").Project.Solution; - solution = solution.AddProject(projectIdWithReference, "WithReference", "WithReference", LanguageNames.CSharp) - .AddProjectReference(projectIdWithReference, new ProjectReference(projectIdWithGenerator)); + var projectIdWithGenerator = solution.ProjectIds.Single(); + var projectIdWithReference = ProjectId.CreateNewId(); - var compilationWithReference = await solution.GetRequiredProject(projectIdWithReference).GetRequiredCompilationAsync(CancellationToken.None); + solution = solution.AddProject(projectIdWithReference, "WithReference", "WithReference", LanguageNames.CSharp) + .AddProjectReference(projectIdWithReference, new ProjectReference(projectIdWithGenerator)); - var compilationReference = Assert.IsAssignableFrom(Assert.Single(compilationWithReference.References)); + var compilationWithReference = await solution.GetRequiredProject(projectIdWithReference).GetRequiredCompilationAsync(CancellationToken.None); - var compilationWithGenerator = await solution.GetRequiredProject(projectIdWithGenerator).GetRequiredCompilationAsync(CancellationToken.None); + var compilationReference = Assert.IsAssignableFrom(Assert.Single(compilationWithReference.References)); - Assert.NotEmpty(compilationWithGenerator.SyntaxTrees); - Assert.Same(compilationWithGenerator, compilationReference.Compilation); - } + var compilationWithGenerator = await solution.GetRequiredProject(projectIdWithGenerator).GetRequiredCompilationAsync(CancellationToken.None); - [Theory, CombinatorialData] - public async Task GetDocumentWithGeneratedTreeReturnsGeneratedDocument(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddAdditionalDocument("Test.txt", "Hello, world!").Project; - - var syntaxTree = Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); - var generatedDocument = Assert.IsType(project.GetDocument(syntaxTree)); - Assert.Same(syntaxTree, await generatedDocument.GetSyntaxTreeAsync()); - } + Assert.NotEmpty(compilationWithGenerator.SyntaxTrees); + Assert.Same(compilationWithGenerator, compilationReference.Compilation); + } - [Theory, CombinatorialData] - public async Task GetDocumentWithGeneratedTreeForInProgressReturnsGeneratedDocument(TestHost testHost) - { - using var workspace = CreateWorkspaceWithPartialSemantics(testHost); - var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project - .AddAdditionalDocument("Test.txt", "Hello, world!").Project; - - // Ensure we've ran generators at least once - await project.GetCompilationAsync(); - - // Produce an in-progress snapshot - project = project.Documents.Single(d => d.Name == "RegularDocument.cs").WithFrozenPartialSemantics(CancellationToken.None).Project; - - // The generated tree should still be there; even if the regular compilation fell away we've now cached the - // generated trees. - var syntaxTree = Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees, t => t.FilePath != "RegularDocument.cs"); - var generatedDocument = Assert.IsType(project.GetDocument(syntaxTree)); - Assert.Same(syntaxTree, await generatedDocument.GetSyntaxTreeAsync()); - } + [Theory, CombinatorialData] + public async Task GetDocumentWithGeneratedTreeReturnsGeneratedDocument(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddAdditionalDocument("Test.txt", "Hello, world!").Project; + + var syntaxTree = Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees); + var generatedDocument = Assert.IsType(project.GetDocument(syntaxTree)); + Assert.Same(syntaxTree, await generatedDocument.GetSyntaxTreeAsync()); + } - [Theory, CombinatorialData] - public async Task TreeReusedIfGeneratedFileDoesNotChangeBetweenRuns(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project - .AddAdditionalDocument("Test.txt", "Hello, world!").Project; + [Theory, CombinatorialData] + public async Task GetDocumentWithGeneratedTreeForInProgressReturnsGeneratedDocument(TestHost testHost) + { + using var workspace = CreateWorkspaceWithPartialSemantics(testHost); + var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project + .AddAdditionalDocument("Test.txt", "Hello, world!").Project; + + // Ensure we've ran generators at least once + await project.GetCompilationAsync(); + + // Produce an in-progress snapshot + project = project.Documents.Single(d => d.Name == "RegularDocument.cs").WithFrozenPartialSemantics(CancellationToken.None).Project; + + // The generated tree should still be there; even if the regular compilation fell away we've now cached the + // generated trees. + var syntaxTree = Assert.Single((await project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees, t => t.FilePath != "RegularDocument.cs"); + var generatedDocument = Assert.IsType(project.GetDocument(syntaxTree)); + Assert.Same(syntaxTree, await generatedDocument.GetSyntaxTreeAsync()); + } - var generatedTreeBeforeChange = await Assert.Single(await project.GetSourceGeneratedDocumentsAsync()).GetSyntaxTreeAsync(); + [Theory, CombinatorialData] + public async Task TreeReusedIfGeneratedFileDoesNotChangeBetweenRuns(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project + .AddAdditionalDocument("Test.txt", "Hello, world!").Project; - // Mutate the regular document to produce a new compilation - project = project.Documents.Single().WithText(SourceText.From("// Change")).Project; + var generatedTreeBeforeChange = await Assert.Single(await project.GetSourceGeneratedDocumentsAsync()).GetSyntaxTreeAsync(); - var generatedTreeAfterChange = await Assert.Single(await project.GetSourceGeneratedDocumentsAsync()).GetSyntaxTreeAsync(); + // Mutate the regular document to produce a new compilation + project = project.Documents.Single().WithText(SourceText.From("// Change")).Project; - Assert.Same(generatedTreeBeforeChange, generatedTreeAfterChange); - } + var generatedTreeAfterChange = await Assert.Single(await project.GetSourceGeneratedDocumentsAsync()).GetSyntaxTreeAsync(); - [Theory, CombinatorialData] - public async Task TreeNotReusedIfParseOptionsChangeChangeBetweenRuns(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project - .AddAdditionalDocument("Test.txt", "Hello, world!").Project; + Assert.Same(generatedTreeBeforeChange, generatedTreeAfterChange); + } - var generatedTreeBeforeChange = await Assert.Single(await project.GetSourceGeneratedDocumentsAsync()).GetSyntaxTreeAsync(); + [Theory, CombinatorialData] + public async Task TreeNotReusedIfParseOptionsChangeChangeBetweenRuns(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project + .AddAdditionalDocument("Test.txt", "Hello, world!").Project; - // Mutate the parse options to produce a new compilation - Assert.NotEqual(DocumentationMode.Diagnose, project.ParseOptions!.DocumentationMode); - project = project.WithParseOptions(project.ParseOptions.WithDocumentationMode(DocumentationMode.Diagnose)); + var generatedTreeBeforeChange = await Assert.Single(await project.GetSourceGeneratedDocumentsAsync()).GetSyntaxTreeAsync(); - var generatedTreeAfterChange = await Assert.Single(await project.GetSourceGeneratedDocumentsAsync()).GetSyntaxTreeAsync(); + // Mutate the parse options to produce a new compilation + Assert.NotEqual(DocumentationMode.Diagnose, project.ParseOptions!.DocumentationMode); + project = project.WithParseOptions(project.ParseOptions.WithDocumentationMode(DocumentationMode.Diagnose)); - Assert.NotSame(generatedTreeBeforeChange, generatedTreeAfterChange); - Assert.Equal(DocumentationMode.Diagnose, generatedTreeAfterChange!.Options.DocumentationMode); - } + var generatedTreeAfterChange = await Assert.Single(await project.GetSourceGeneratedDocumentsAsync()).GetSyntaxTreeAsync(); - [Theory, CombinatorialData] - public async Task ChangeToDocumentThatDoesNotImpactGeneratedDocumentReusesDeclarationTree(bool generatorProducesTree, TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); + Assert.NotSame(generatedTreeBeforeChange, generatedTreeAfterChange); + Assert.Equal(DocumentationMode.Diagnose, generatedTreeAfterChange!.Options.DocumentationMode); + } - // We'll use either a generator that produces a single tree, or no tree, to ensure we efficiently handle both cases - ISourceGenerator generator = generatorProducesTree ? new SingleFileTestGenerator("// StaticContent") - : new CallbackGenerator(onInit: _ => { }, onExecute: _ => { }); + [Theory, CombinatorialData] + public async Task ChangeToDocumentThatDoesNotImpactGeneratedDocumentReusesDeclarationTree(bool generatorProducesTree, TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(generator); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project; + // We'll use either a generator that produces a single tree, or no tree, to ensure we efficiently handle both cases + ISourceGenerator generator = generatorProducesTree ? new SingleFileTestGenerator("// StaticContent") + : new CallbackGenerator(onInit: _ => { }, onExecute: _ => { }); - // Ensure we already have a compilation created - _ = await project.GetCompilationAsync(); + var analyzerReference = new TestGeneratorReference(generator); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project; - project = await MakeChangesToDocument(project); + // Ensure we already have a compilation created + _ = await project.GetCompilationAsync(); - var compilationAfterFirstChange = await project.GetRequiredCompilationAsync(CancellationToken.None); + project = await MakeChangesToDocument(project); - project = await MakeChangesToDocument(project); + var compilationAfterFirstChange = await project.GetRequiredCompilationAsync(CancellationToken.None); - var compilationAfterSecondChange = await project.GetRequiredCompilationAsync(CancellationToken.None); + project = await MakeChangesToDocument(project); - // When we produced compilationAfterSecondChange, what we would ideally like is that compilation was produced by taking - // compilationAfterFirstChange and simply updating the syntax tree that changed, since the generated documents didn't change. - // That allows the compiler to reuse the same declaration tree for the generated file. This is hard to observe directly, but if we reflect - // into the Compilation we can see if the declaration tree is untouched. We won't look at the original compilation, since - // that original one was produced by adding the generated file as the final step, so it's cache won't be reusable, since the - // compiler separates the "most recently changed tree" in the declaration table for efficiency. + var compilationAfterSecondChange = await project.GetRequiredCompilationAsync(CancellationToken.None); - var cachedStateAfterFirstChange = GetDeclarationManagerCachedStateForUnchangingTrees(compilationAfterFirstChange); - var cachedStateAfterSecondChange = GetDeclarationManagerCachedStateForUnchangingTrees(compilationAfterSecondChange); + // When we produced compilationAfterSecondChange, what we would ideally like is that compilation was produced by taking + // compilationAfterFirstChange and simply updating the syntax tree that changed, since the generated documents didn't change. + // That allows the compiler to reuse the same declaration tree for the generated file. This is hard to observe directly, but if we reflect + // into the Compilation we can see if the declaration tree is untouched. We won't look at the original compilation, since + // that original one was produced by adding the generated file as the final step, so it's cache won't be reusable, since the + // compiler separates the "most recently changed tree" in the declaration table for efficiency. - Assert.Same(cachedStateAfterFirstChange, cachedStateAfterSecondChange); + var cachedStateAfterFirstChange = GetDeclarationManagerCachedStateForUnchangingTrees(compilationAfterFirstChange); + var cachedStateAfterSecondChange = GetDeclarationManagerCachedStateForUnchangingTrees(compilationAfterSecondChange); - static object GetDeclarationManagerCachedStateForUnchangingTrees(Compilation compilation) - { - var syntaxAndDeclarationsManager = compilation.GetFieldValue("_syntaxAndDeclarations"); - var state = syntaxAndDeclarationsManager.GetType().GetMethod("GetLazyState", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!.Invoke(syntaxAndDeclarationsManager, null); - var declarationTable = state.GetFieldValue("DeclarationTable"); - return declarationTable.GetFieldValue("_cache"); - } + Assert.Same(cachedStateAfterFirstChange, cachedStateAfterSecondChange); - static async Task MakeChangesToDocument(Project project) - { - var existingText = await project.Documents.Single().GetTextAsync(); - var newText = existingText.WithChanges(new TextChange(new TextSpan(existingText.Length, length: 0), " With Change")); - project = project.Documents.Single().WithText(newText).Project; - return project; - } + static object GetDeclarationManagerCachedStateForUnchangingTrees(Compilation compilation) + { + var syntaxAndDeclarationsManager = compilation.GetFieldValue("_syntaxAndDeclarations"); + var state = syntaxAndDeclarationsManager.GetType().GetMethod("GetLazyState", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!.Invoke(syntaxAndDeclarationsManager, null); + var declarationTable = state.GetFieldValue("DeclarationTable"); + return declarationTable.GetFieldValue("_cache"); } - [Theory, CombinatorialData] - public async Task CompilationNotCreatedByFetchingGeneratedFilesIfNoGeneratorsPresent(TestHost testHost) + static async Task MakeChangesToDocument(Project project) { - using var workspace = CreateWorkspace(testHost: testHost); - var project = AddEmptyProject(workspace.CurrentSolution); + var existingText = await project.Documents.Single().GetTextAsync(); + var newText = existingText.WithChanges(new TextChange(new TextSpan(existingText.Length, length: 0), " With Change")); + project = project.Documents.Single().WithText(newText).Project; + return project; + } + } - Assert.Empty(await project.GetSourceGeneratedDocumentsAsync()); + [Theory, CombinatorialData] + public async Task CompilationNotCreatedByFetchingGeneratedFilesIfNoGeneratorsPresent(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var project = AddEmptyProject(workspace.CurrentSolution); - // We shouldn't have any compilation since we didn't have to run anything - Assert.False(project.TryGetCompilation(out _)); - } + Assert.Empty(await project.GetSourceGeneratedDocumentsAsync()); - [Theory, CombinatorialData] - public async Task OpenSourceGeneratedUpdatedToBufferContentsWhenCallingGetOpenDocumentInCurrentContextWithChanges(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference); + // We shouldn't have any compilation since we didn't have to run anything + Assert.False(project.TryGetCompilation(out _)); + } - Assert.True(workspace.SetCurrentSolution(_ => project.Solution, WorkspaceChangeKind.SolutionChanged)); + [Theory, CombinatorialData] + public async Task OpenSourceGeneratedUpdatedToBufferContentsWhenCallingGetOpenDocumentInCurrentContextWithChanges(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference); - var generatedDocument = Assert.Single(await project.GetSourceGeneratedDocumentsAsync()); - var differentOpenTextContainer = SourceText.From("// Open Text").Container; + Assert.True(workspace.SetCurrentSolution(_ => project.Solution, WorkspaceChangeKind.SolutionChanged)); - workspace.OnSourceGeneratedDocumentOpened(differentOpenTextContainer, generatedDocument); + var generatedDocument = Assert.Single(await project.GetSourceGeneratedDocumentsAsync()); + var differentOpenTextContainer = SourceText.From("// Open Text").Container; - generatedDocument = Assert.IsType(differentOpenTextContainer.CurrentText.GetOpenDocumentInCurrentContextWithChanges()); - Assert.Same(differentOpenTextContainer.CurrentText, await generatedDocument.GetTextAsync()); - Assert.NotSame(workspace.CurrentSolution, generatedDocument.Project.Solution); + workspace.OnSourceGeneratedDocumentOpened(differentOpenTextContainer, generatedDocument); - var generatedTree = await generatedDocument.GetSyntaxTreeAsync(); - var compilation = await generatedDocument.Project.GetRequiredCompilationAsync(CancellationToken.None); - Assert.Contains(generatedTree, compilation.SyntaxTrees); - } + generatedDocument = Assert.IsType(differentOpenTextContainer.CurrentText.GetOpenDocumentInCurrentContextWithChanges()); + Assert.Same(differentOpenTextContainer.CurrentText, await generatedDocument.GetTextAsync()); + Assert.NotSame(workspace.CurrentSolution, generatedDocument.Project.Solution); - [Theory, CombinatorialData] - public async Task OpenSourceGeneratedFileDoesNotCreateNewSnapshotIfContentsKnownToMatch(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference); + var generatedTree = await generatedDocument.GetSyntaxTreeAsync(); + var compilation = await generatedDocument.Project.GetRequiredCompilationAsync(CancellationToken.None); + Assert.Contains(generatedTree, compilation.SyntaxTrees); + } - Assert.True(workspace.SetCurrentSolution(_ => project.Solution, WorkspaceChangeKind.SolutionChanged)); + [Theory, CombinatorialData] + public async Task OpenSourceGeneratedFileDoesNotCreateNewSnapshotIfContentsKnownToMatch(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference); - var generatedDocument = Assert.Single(await workspace.CurrentSolution.Projects.Single().GetSourceGeneratedDocumentsAsync()); - var differentOpenTextContainer = SourceText.From("// StaticContent", Encoding.UTF8).Container; + Assert.True(workspace.SetCurrentSolution(_ => project.Solution, WorkspaceChangeKind.SolutionChanged)); - workspace.OnSourceGeneratedDocumentOpened(differentOpenTextContainer, generatedDocument); + var generatedDocument = Assert.Single(await workspace.CurrentSolution.Projects.Single().GetSourceGeneratedDocumentsAsync()); + var differentOpenTextContainer = SourceText.From("// StaticContent", Encoding.UTF8).Container; - generatedDocument = Assert.IsType(differentOpenTextContainer.CurrentText.GetOpenDocumentInCurrentContextWithChanges()); - Assert.Same(workspace.CurrentSolution, generatedDocument!.Project.Solution); - } + workspace.OnSourceGeneratedDocumentOpened(differentOpenTextContainer, generatedDocument); - [Theory, CombinatorialData] - public async Task OpenSourceGeneratedFileMatchesBufferContentsEvenIfGeneratedFileIsMissingIsRemoved(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); - var originalAdditionalFile = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddAdditionalDocument("Test.txt", SourceText.From("")); + generatedDocument = Assert.IsType(differentOpenTextContainer.CurrentText.GetOpenDocumentInCurrentContextWithChanges()); + Assert.Same(workspace.CurrentSolution, generatedDocument!.Project.Solution); + } - Assert.True(workspace.SetCurrentSolution(_ => originalAdditionalFile.Project.Solution, WorkspaceChangeKind.SolutionChanged)); + [Theory, CombinatorialData] + public async Task OpenSourceGeneratedFileMatchesBufferContentsEvenIfGeneratedFileIsMissingIsRemoved(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new GenerateFileForEachAdditionalFileWithContentsCommented()); + var originalAdditionalFile = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddAdditionalDocument("Test.txt", SourceText.From("")); - var generatedDocument = Assert.Single(await originalAdditionalFile.Project.GetSourceGeneratedDocumentsAsync()); - var differentOpenTextContainer = SourceText.From("// Open Text").Container; + Assert.True(workspace.SetCurrentSolution(_ => originalAdditionalFile.Project.Solution, WorkspaceChangeKind.SolutionChanged)); - workspace.OnSourceGeneratedDocumentOpened(differentOpenTextContainer, generatedDocument); - workspace.OnAdditionalDocumentRemoved(originalAdditionalFile.Id); + var generatedDocument = Assert.Single(await originalAdditionalFile.Project.GetSourceGeneratedDocumentsAsync()); + var differentOpenTextContainer = SourceText.From("// Open Text").Container; - // At this point there should be no generated documents, even though our file is still open - Assert.Empty(await workspace.CurrentSolution.Projects.Single().GetSourceGeneratedDocumentsAsync()); + workspace.OnSourceGeneratedDocumentOpened(differentOpenTextContainer, generatedDocument); + workspace.OnAdditionalDocumentRemoved(originalAdditionalFile.Id); - generatedDocument = Assert.IsType(differentOpenTextContainer.CurrentText.GetOpenDocumentInCurrentContextWithChanges()); - Assert.Same(differentOpenTextContainer.CurrentText, await generatedDocument.GetTextAsync()); + // At this point there should be no generated documents, even though our file is still open + Assert.Empty(await workspace.CurrentSolution.Projects.Single().GetSourceGeneratedDocumentsAsync()); - var generatedTree = await generatedDocument.GetSyntaxTreeAsync(); - var compilation = await generatedDocument.Project.GetRequiredCompilationAsync(CancellationToken.None); - Assert.Contains(generatedTree, compilation.SyntaxTrees); - } + generatedDocument = Assert.IsType(differentOpenTextContainer.CurrentText.GetOpenDocumentInCurrentContextWithChanges()); + Assert.Same(differentOpenTextContainer.CurrentText, await generatedDocument.GetTextAsync()); - [Theory, CombinatorialData] - public async Task OpenSourceGeneratedDocumentUpdatedAndVisibleInProjectReference(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); - var solution = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference).Solution; - var projectIdWithGenerator = solution.ProjectIds.Single(); + var generatedTree = await generatedDocument.GetSyntaxTreeAsync(); + var compilation = await generatedDocument.Project.GetRequiredCompilationAsync(CancellationToken.None); + Assert.Contains(generatedTree, compilation.SyntaxTrees); + } - solution = AddEmptyProject(solution).AddProjectReference( - new ProjectReference(projectIdWithGenerator)).Solution; + [Theory, CombinatorialData] + public async Task OpenSourceGeneratedDocumentUpdatedAndVisibleInProjectReference(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); + var solution = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference).Solution; + var projectIdWithGenerator = solution.ProjectIds.Single(); - Assert.True(workspace.SetCurrentSolution(_ => solution, WorkspaceChangeKind.SolutionChanged)); + solution = AddEmptyProject(solution).AddProjectReference( + new ProjectReference(projectIdWithGenerator)).Solution; - var generatedDocument = Assert.Single(await workspace.CurrentSolution.GetRequiredProject(projectIdWithGenerator).GetSourceGeneratedDocumentsAsync()); - var differentOpenTextContainer = SourceText.From("// Open Text").Container; + Assert.True(workspace.SetCurrentSolution(_ => solution, WorkspaceChangeKind.SolutionChanged)); - workspace.OnSourceGeneratedDocumentOpened(differentOpenTextContainer, generatedDocument); + var generatedDocument = Assert.Single(await workspace.CurrentSolution.GetRequiredProject(projectIdWithGenerator).GetSourceGeneratedDocumentsAsync()); + var differentOpenTextContainer = SourceText.From("// Open Text").Container; - generatedDocument = Assert.IsType(differentOpenTextContainer.CurrentText.GetOpenDocumentInCurrentContextWithChanges()); - var generatedTree = await generatedDocument.GetSyntaxTreeAsync(); + workspace.OnSourceGeneratedDocumentOpened(differentOpenTextContainer, generatedDocument); - // Fetch the compilation from the other project, it should have a compilation reference that - // contains the generated tree - var projectWithReference = generatedDocument.Project.Solution.Projects.Single(p => p.Id != projectIdWithGenerator); - var compilationWithReference = await projectWithReference.GetRequiredCompilationAsync(CancellationToken.None); - var compilationReference = Assert.Single(compilationWithReference.References.OfType()); + generatedDocument = Assert.IsType(differentOpenTextContainer.CurrentText.GetOpenDocumentInCurrentContextWithChanges()); + var generatedTree = await generatedDocument.GetSyntaxTreeAsync(); - Assert.Contains(generatedTree, compilationReference.Compilation.SyntaxTrees); - } + // Fetch the compilation from the other project, it should have a compilation reference that + // contains the generated tree + var projectWithReference = generatedDocument.Project.Solution.Projects.Single(p => p.Id != projectIdWithGenerator); + var compilationWithReference = await projectWithReference.GetRequiredCompilationAsync(CancellationToken.None); + var compilationReference = Assert.Single(compilationWithReference.References.OfType()); - [Theory, CombinatorialData] - public async Task OpenSourceGeneratedDocumentsUpdateIsDocumentOpenAndCloseWorks(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference); + Assert.Contains(generatedTree, compilationReference.Compilation.SyntaxTrees); + } - Assert.True(workspace.SetCurrentSolution(_ => project.Solution, WorkspaceChangeKind.SolutionChanged)); + [Theory, CombinatorialData] + public async Task OpenSourceGeneratedDocumentsUpdateIsDocumentOpenAndCloseWorks(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference(new SingleFileTestGenerator("// StaticContent")); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference); - var generatedDocument = Assert.Single(await project.GetSourceGeneratedDocumentsAsync()); - var differentOpenTextContainer = SourceText.From("// Open Text").Container; + Assert.True(workspace.SetCurrentSolution(_ => project.Solution, WorkspaceChangeKind.SolutionChanged)); - workspace.OnSourceGeneratedDocumentOpened(differentOpenTextContainer, generatedDocument); + var generatedDocument = Assert.Single(await project.GetSourceGeneratedDocumentsAsync()); + var differentOpenTextContainer = SourceText.From("// Open Text").Container; - Assert.True(workspace.IsDocumentOpen(generatedDocument.Identity.DocumentId)); + workspace.OnSourceGeneratedDocumentOpened(differentOpenTextContainer, generatedDocument); - var document = await workspace.CurrentSolution.GetSourceGeneratedDocumentAsync(generatedDocument.Identity.DocumentId, CancellationToken.None); - Contract.ThrowIfNull(document); - workspace.OnSourceGeneratedDocumentClosed(document); + Assert.True(workspace.IsDocumentOpen(generatedDocument.Identity.DocumentId)); - Assert.False(workspace.IsDocumentOpen(generatedDocument.Identity.DocumentId)); - Assert.Null(differentOpenTextContainer.CurrentText.GetOpenDocumentInCurrentContextWithChanges()); - } + var document = await workspace.CurrentSolution.GetSourceGeneratedDocumentAsync(generatedDocument.Identity.DocumentId, CancellationToken.None); + Contract.ThrowIfNull(document); + workspace.OnSourceGeneratedDocumentClosed(document); + + Assert.False(workspace.IsDocumentOpen(generatedDocument.Identity.DocumentId)); + Assert.Null(differentOpenTextContainer.CurrentText.GetOpenDocumentInCurrentContextWithChanges()); + } + + [Theory, CombinatorialData] + public async Task FreezingSolutionEnsuresGeneratorsDoNotRun(bool forkBeforeFreeze, TestHost testHost) + { + var generatorRan = false; + var generator = new CallbackGenerator(onInit: _ => { }, onExecute: _ => { generatorRan = true; }); + + using var workspace = CreateWorkspaceWithPartialSemantics(testHost); + var analyzerReference = new TestGeneratorReference(generator); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project; + + Assert.True(workspace.SetCurrentSolution(_ => project.Solution, WorkspaceChangeKind.SolutionChanged)); + + var documentToFreeze = workspace.CurrentSolution.Projects.Single().Documents.Single(); - [Theory, CombinatorialData] - public async Task FreezingSolutionEnsuresGeneratorsDoNotRun(bool forkBeforeFreeze, TestHost testHost) + // The generator shouldn't have ran before any of this since we didn't do anything that would ask for a compilation + Assert.False(generatorRan); + + if (forkBeforeFreeze) { - var generatorRan = false; - var generator = new CallbackGenerator(onInit: _ => { }, onExecute: _ => { generatorRan = true; }); + // Forking before freezing means we'll have to do extra work to produce the final compilation, but we should still + // not be running generators + documentToFreeze = documentToFreeze.WithText(SourceText.From("// Changed Source File")); + } - using var workspace = CreateWorkspaceWithPartialSemantics(testHost); - var analyzerReference = new TestGeneratorReference(generator); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project; + var frozenDocument = documentToFreeze.WithFrozenPartialSemantics(CancellationToken.None); + Assert.NotSame(frozenDocument, documentToFreeze); + await frozenDocument.GetSemanticModelAsync(CancellationToken.None); - Assert.True(workspace.SetCurrentSolution(_ => project.Solution, WorkspaceChangeKind.SolutionChanged)); + Assert.False(generatorRan); + } - var documentToFreeze = workspace.CurrentSolution.Projects.Single().Documents.Single(); + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/56702")] + public async Task ForkAfterFreezeNoLongerRunsGenerators(TestHost testHost) + { + using var workspace = CreateWorkspaceWithPartialSemantics(testHost); + var generatorRan = false; + var analyzerReference = new TestGeneratorReference(new CallbackGenerator(_ => { }, onExecute: _ => { generatorRan = true; }, source: "// Hello World!")); + var project = AddEmptyProject(workspace.CurrentSolution) + .AddAnalyzerReference(analyzerReference) + .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project; - // The generator shouldn't have ran before any of this since we didn't do anything that would ask for a compilation - Assert.False(generatorRan); + // Ensure generators are ran + var objectReference = await project.GetCompilationAsync(); - if (forkBeforeFreeze) - { - // Forking before freezing means we'll have to do extra work to produce the final compilation, but we should still - // not be running generators - documentToFreeze = documentToFreeze.WithText(SourceText.From("// Changed Source File")); - } + Assert.True(generatorRan); + generatorRan = false; - var frozenDocument = documentToFreeze.WithFrozenPartialSemantics(CancellationToken.None); - Assert.NotSame(frozenDocument, documentToFreeze); - await frozenDocument.GetSemanticModelAsync(CancellationToken.None); + var document = project.Documents.Single().WithFrozenPartialSemantics(CancellationToken.None); - Assert.False(generatorRan); - } + // And fork with new contents; we'll ensure the contents of this tree are different, but the generator will still not be ran + document = document.WithText(SourceText.From("// Something else")); - [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/56702")] - public async Task ForkAfterFreezeNoLongerRunsGenerators(TestHost testHost) - { - using var workspace = CreateWorkspaceWithPartialSemantics(testHost); - var generatorRan = false; - var analyzerReference = new TestGeneratorReference(new CallbackGenerator(_ => { }, onExecute: _ => { generatorRan = true; }, source: "// Hello World!")); - var project = AddEmptyProject(workspace.CurrentSolution) - .AddAnalyzerReference(analyzerReference) - .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project; + var compilation = await document.Project.GetRequiredCompilationAsync(CancellationToken.None); + Assert.Equal(2, compilation.SyntaxTrees.Count()); + Assert.False(generatorRan); - // Ensure generators are ran - var objectReference = await project.GetCompilationAsync(); + Assert.Equal("// Something else", (await document.GetRequiredSyntaxRootAsync(CancellationToken.None)).ToFullString()); + } - Assert.True(generatorRan); - generatorRan = false; + [Theory, CombinatorialData] + public async Task LinkedDocumentOfFrozenShouldNotRunSourceGenerator(TestHost testHost) + { + using var workspace = CreateWorkspaceWithPartialSemantics(testHost); + var generatorRan = false; + var analyzerReference = new TestGeneratorReference(new CallbackGenerator(_ => { }, onExecute: _ => { generatorRan = true; }, source: "// Hello World!")); - var document = project.Documents.Single().WithFrozenPartialSemantics(CancellationToken.None); + var originalDocument1 = AddEmptyProject(workspace.CurrentSolution, name: "Project1") + .AddAnalyzerReference(analyzerReference) + .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs"); - // And fork with new contents; we'll ensure the contents of this tree are different, but the generator will still not be ran + // this is a linked document of document1 above + var originalDocument2 = AddEmptyProject(originalDocument1.Project.Solution, name: "Project2") + .AddAnalyzerReference(analyzerReference) + .AddDocument(originalDocument1.Name, await originalDocument1.GetTextAsync().ConfigureAwait(false), filePath: originalDocument1.FilePath); + + var frozenSolution = originalDocument2.WithFrozenPartialSemantics(CancellationToken.None).Project.Solution; + var documentIdsToTest = new[] { originalDocument1.Id, originalDocument2.Id }; + + foreach (var documentIdToTest in documentIdsToTest) + { + var document = frozenSolution.GetRequiredDocument(documentIdToTest); + Assert.Single(document.GetLinkedDocumentIds()); + + Assert.Equal(document.GetLinkedDocumentIds().Single(), documentIdsToTest.Except([documentIdToTest]).Single()); document = document.WithText(SourceText.From("// Something else")); var compilation = await document.Project.GetRequiredCompilationAsync(CancellationToken.None); - Assert.Equal(2, compilation.SyntaxTrees.Count()); + Assert.Single(compilation.SyntaxTrees); Assert.False(generatorRan); - - Assert.Equal("// Something else", (await document.GetRequiredSyntaxRootAsync(CancellationToken.None)).ToFullString()); } + } - [Theory, CombinatorialData] - public async Task LinkedDocumentOfFrozenShouldNotRunSourceGenerator(TestHost testHost) - { - using var workspace = CreateWorkspaceWithPartialSemantics(testHost); - var generatorRan = false; - var analyzerReference = new TestGeneratorReference(new CallbackGenerator(_ => { }, onExecute: _ => { generatorRan = true; }, source: "// Hello World!")); + [Theory, CombinatorialData] + public async Task DynamicFilesNotPassedToSourceGenerators(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); - var originalDocument1 = AddEmptyProject(workspace.CurrentSolution, name: "Project1") - .AddAnalyzerReference(analyzerReference) - .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs"); + bool? noTreesPassed = null; - // this is a linked document of document1 above - var originalDocument2 = AddEmptyProject(originalDocument1.Project.Solution, name: "Project2") - .AddAnalyzerReference(analyzerReference) - .AddDocument(originalDocument1.Name, await originalDocument1.GetTextAsync().ConfigureAwait(false), filePath: originalDocument1.FilePath); + var analyzerReference = new TestGeneratorReference( + new CallbackGenerator( + onInit: _ => { }, + onExecute: context => noTreesPassed = context.Compilation.SyntaxTrees.Any())); - var frozenSolution = originalDocument2.WithFrozenPartialSemantics(CancellationToken.None).Project.Solution; - var documentIdsToTest = new[] { originalDocument1.Id, originalDocument2.Id }; + var project = AddEmptyProject(workspace.CurrentSolution); + var documentInfo = DocumentInfo.Create( + DocumentId.CreateNewId(project.Id), + name: "Test.cs", + isGenerated: true).WithDesignTimeOnly(true); - foreach (var documentIdToTest in documentIdsToTest) - { - var document = frozenSolution.GetRequiredDocument(documentIdToTest); - Assert.Single(document.GetLinkedDocumentIds()); + project = project.Solution.AddDocument(documentInfo).Projects.Single() + .AddAnalyzerReference(analyzerReference); - Assert.Equal(document.GetLinkedDocumentIds().Single(), documentIdsToTest.Except([documentIdToTest]).Single()); - document = document.WithText(SourceText.From("// Something else")); + _ = await project.GetCompilationAsync(); - var compilation = await document.Project.GetRequiredCompilationAsync(CancellationToken.None); - Assert.Single(compilation.SyntaxTrees); - Assert.False(generatorRan); - } - } + // We should have ran the generator, and it should not have had any trees + Assert.True(noTreesPassed.HasValue); + Assert.False(noTreesPassed!.Value); + } - [Theory, CombinatorialData] - public async Task DynamicFilesNotPassedToSourceGenerators(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); + [Theory, CombinatorialData] + public async Task FreezingSourceGeneratedDocumentsWorks(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); - bool? noTreesPassed = null; + var analyzerReference = new TestGeneratorReference( + new SingleFileTestGenerator("// Hello, World")); - var analyzerReference = new TestGeneratorReference( - new CallbackGenerator( - onInit: _ => { }, - onExecute: context => noTreesPassed = context.Compilation.SyntaxTrees.Any())); + var project = AddEmptyProject(workspace.CurrentSolution).AddAnalyzerReference(analyzerReference); - var project = AddEmptyProject(workspace.CurrentSolution); - var documentInfo = DocumentInfo.Create( - DocumentId.CreateNewId(project.Id), - name: "Test.cs", - isGenerated: true).WithDesignTimeOnly(true); + var sourceGeneratedDocument = Assert.Single(await project.GetSourceGeneratedDocumentsAsync()); + var sourceGeneratedDocumentIdentity = sourceGeneratedDocument.Identity; - project = project.Solution.AddDocument(documentInfo).Projects.Single() - .AddAnalyzerReference(analyzerReference); + // Do some assertions with freezing that document + await AssertFrozen(project, sourceGeneratedDocumentIdentity); - _ = await project.GetCompilationAsync(); + // Now remove the generator, and ensure we can freeze it even if it's not there. This scenario exists for IDEs where + // a text buffer might still be wired up to the workspace and we're invoking a feature on it. The generated document might have gone + // away, but we don't know that synchronously. + project = project.RemoveAnalyzerReference(analyzerReference); + await AssertFrozen(project, sourceGeneratedDocumentIdentity); - // We should have ran the generator, and it should not have had any trees - Assert.True(noTreesPassed.HasValue); - Assert.False(noTreesPassed!.Value); + static async Task AssertFrozen(Project project, SourceGeneratedDocumentIdentity identity) + { + var frozenWithSingleDocument = project.Solution.WithFrozenSourceGeneratedDocument( + identity, DateTime.Now, SourceText.From("// Frozen Document")); + Assert.Equal("// Frozen Document", (await frozenWithSingleDocument.GetTextAsync()).ToString()); + var syntaxTrees = (await frozenWithSingleDocument.Project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees; + var frozenTree = Assert.Single(syntaxTrees); + Assert.Equal("// Frozen Document", frozenTree.ToString()); } + } - [Theory, CombinatorialData] - public async Task FreezingSourceGeneratedDocumentsWorks(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); + [Theory, CombinatorialData] + public async Task FreezingSourceGeneratedDocumentsInTwoProjectsWorks(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); - var analyzerReference = new TestGeneratorReference( - new SingleFileTestGenerator("// Hello, World")); + var analyzerReference = new TestGeneratorReference( + new SingleFileTestGenerator("// Hello, World")); - var project = AddEmptyProject(workspace.CurrentSolution).AddAnalyzerReference(analyzerReference); + var solution = AddEmptyProject(workspace.CurrentSolution).AddAnalyzerReference(analyzerReference).Solution; + var projectId1 = solution.ProjectIds.Single(); + var project2 = AddEmptyProject(solution, name: "TestProject2").AddAnalyzerReference(analyzerReference); + solution = project2.Solution; + var projectId2 = project2.Id; - var sourceGeneratedDocument = Assert.Single(await project.GetSourceGeneratedDocumentsAsync()); - var sourceGeneratedDocumentIdentity = sourceGeneratedDocument.Identity; + var sourceGeneratedDocument1 = Assert.Single(await solution.GetRequiredProject(projectId1).GetSourceGeneratedDocumentsAsync()); + var sourceGeneratedDocument2 = Assert.Single(await solution.GetRequiredProject(projectId2).GetSourceGeneratedDocumentsAsync()); - // Do some assertions with freezing that document - await AssertFrozen(project, sourceGeneratedDocumentIdentity); + // And now freeze both of them at once + var solutionWithFrozenDocuments = solution.WithFrozenSourceGeneratedDocuments( + [(sourceGeneratedDocument1.Identity, DateTime.Now, SourceText.From("// Frozen 1")), (sourceGeneratedDocument2.Identity, DateTime.Now, SourceText.From("// Frozen 2"))]); - // Now remove the generator, and ensure we can freeze it even if it's not there. This scenario exists for IDEs where - // a text buffer might still be wired up to the workspace and we're invoking a feature on it. The generated document might have gone - // away, but we don't know that synchronously. - project = project.RemoveAnalyzerReference(analyzerReference); - await AssertFrozen(project, sourceGeneratedDocumentIdentity); + Assert.Equal("// Frozen 1", (await (await solutionWithFrozenDocuments.GetRequiredProject(projectId1).GetSourceGeneratedDocumentsAsync()).Single().GetTextAsync()).ToString()); + Assert.Equal("// Frozen 2", (await (await solutionWithFrozenDocuments.GetRequiredProject(projectId2).GetSourceGeneratedDocumentsAsync()).Single().GetTextAsync()).ToString()); + } - static async Task AssertFrozen(Project project, SourceGeneratedDocumentIdentity identity) - { - var frozenWithSingleDocument = project.Solution.WithFrozenSourceGeneratedDocument( - identity, DateTime.Now, SourceText.From("// Frozen Document")); - Assert.Equal("// Frozen Document", (await frozenWithSingleDocument.GetTextAsync()).ToString()); - var syntaxTrees = (await frozenWithSingleDocument.Project.GetRequiredCompilationAsync(CancellationToken.None)).SyntaxTrees; - var frozenTree = Assert.Single(syntaxTrees); - Assert.Equal("// Frozen Document", frozenTree.ToString()); - } - } + [Theory, CombinatorialData] + public async Task FreezingWithSameContentDoesNotFork(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); - [Theory, CombinatorialData] - public async Task FreezingSourceGeneratedDocumentsInTwoProjectsWorks(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); + var analyzerReference = new TestGeneratorReference( + new SingleFileTestGenerator("// Hello, World")); - var analyzerReference = new TestGeneratorReference( - new SingleFileTestGenerator("// Hello, World")); + var project = AddEmptyProject(workspace.CurrentSolution).AddAnalyzerReference(analyzerReference); - var solution = AddEmptyProject(workspace.CurrentSolution).AddAnalyzerReference(analyzerReference).Solution; - var projectId1 = solution.ProjectIds.Single(); - var project2 = AddEmptyProject(solution, name: "TestProject2").AddAnalyzerReference(analyzerReference); - solution = project2.Solution; - var projectId2 = project2.Id; + var sourceGeneratedDocument = Assert.Single(await project.GetSourceGeneratedDocumentsAsync()); + var sourceGeneratedDocumentIdentity = sourceGeneratedDocument.Identity; - var sourceGeneratedDocument1 = Assert.Single(await solution.GetRequiredProject(projectId1).GetSourceGeneratedDocumentsAsync()); - var sourceGeneratedDocument2 = Assert.Single(await solution.GetRequiredProject(projectId2).GetSourceGeneratedDocumentsAsync()); + var frozenSolution = project.Solution.WithFrozenSourceGeneratedDocument( + sourceGeneratedDocumentIdentity, sourceGeneratedDocument.GenerationDateTime, SourceText.From("// Hello, World")); + Assert.Same(project.Solution, frozenSolution.Project.Solution); + } - // And now freeze both of them at once - var solutionWithFrozenDocuments = solution.WithFrozenSourceGeneratedDocuments( - [(sourceGeneratedDocument1.Identity, DateTime.Now, SourceText.From("// Frozen 1")), (sourceGeneratedDocument2.Identity, DateTime.Now, SourceText.From("// Frozen 2"))]); + [Theory, CombinatorialData] + public async Task TestChangingGeneratorChangesChecksum(TestHost testHost) + { + using var workspace = CreateWorkspace(testHost: testHost); - Assert.Equal("// Frozen 1", (await (await solutionWithFrozenDocuments.GetRequiredProject(projectId1).GetSourceGeneratedDocumentsAsync()).Single().GetTextAsync()).ToString()); - Assert.Equal("// Frozen 2", (await (await solutionWithFrozenDocuments.GetRequiredProject(projectId2).GetSourceGeneratedDocumentsAsync()).Single().GetTextAsync()).ToString()); - } + var analyzerReference1 = new TestGeneratorReference( + new SingleFileTestGenerator("// Hello, World 1")); + var analyzerReference2 = new TestGeneratorReference( + new SingleFileTestGenerator("// Hello, World 2")); - [Theory, CombinatorialData] - public async Task FreezingWithSameContentDoesNotFork(TestHost testHost) - { - using var workspace = CreateWorkspace(testHost: testHost); + var project0 = AddEmptyProject(workspace.CurrentSolution); + var checksum0 = await project0.Solution.SolutionState.GetChecksumAsync(CancellationToken.None); - var analyzerReference = new TestGeneratorReference( - new SingleFileTestGenerator("// Hello, World")); + var project1 = project0.AddAnalyzerReference(analyzerReference1); + var checksum1 = await project1.Solution.SolutionState.GetChecksumAsync(CancellationToken.None); - var project = AddEmptyProject(workspace.CurrentSolution).AddAnalyzerReference(analyzerReference); + Assert.NotEqual(project0, project1); + Assert.NotEqual(checksum0, checksum1); - var sourceGeneratedDocument = Assert.Single(await project.GetSourceGeneratedDocumentsAsync()); - var sourceGeneratedDocumentIdentity = sourceGeneratedDocument.Identity; + var project2 = project1.RemoveAnalyzerReference(analyzerReference1); + var checksum2 = await project2.Solution.SolutionState.GetChecksumAsync(CancellationToken.None); - var frozenSolution = project.Solution.WithFrozenSourceGeneratedDocument( - sourceGeneratedDocumentIdentity, sourceGeneratedDocument.GenerationDateTime, SourceText.From("// Hello, World")); - Assert.Same(project.Solution, frozenSolution.Project.Solution); - } + Assert.NotEqual(project0, project2); + Assert.NotEqual(project1, project2); + + // Should still have the same checksum that we started with, even though we have different project instances. + Assert.Equal(checksum0, checksum2); + Assert.NotEqual(checksum1, checksum2); + + var project3 = project2.AddAnalyzerReference(analyzerReference2); + var checksum3 = await project3.Solution.SolutionState.GetChecksumAsync(CancellationToken.None); + + Assert.NotEqual(project0, project3); + Assert.NotEqual(project1, project3); + Assert.NotEqual(project2, project3); + Assert.NotEqual(checksum0, checksum3); + Assert.NotEqual(checksum1, checksum3); + Assert.NotEqual(checksum2, checksum3); } } diff --git a/src/Workspaces/CoreTest/SyntaxNodeTests.cs b/src/Workspaces/CoreTest/SyntaxNodeTests.cs index bdf2730eb9843..6de35b454257f 100644 --- a/src/Workspaces/CoreTest/SyntaxNodeTests.cs +++ b/src/Workspaces/CoreTest/SyntaxNodeTests.cs @@ -30,7 +30,7 @@ public async Task TestReplaceOneNodeAsync() var root = tree.GetRoot(); var node = root.DescendantNodes().OfType().Single(); - var newRoot = await root.ReplaceNodesAsync(new[] { node }, (o, n, c) => + var newRoot = await root.ReplaceNodesAsync([node], (o, n, c) => { var decl = (VariableDeclaratorSyntax)n; return Task.FromResult(decl.WithIdentifier(SyntaxFactory.Identifier("Y"))); diff --git a/src/Workspaces/CoreTest/TestCompositionTests.cs b/src/Workspaces/CoreTest/TestCompositionTests.cs index 24535fa007888..3f4a47093aa9e 100644 --- a/src/Workspaces/CoreTest/TestCompositionTests.cs +++ b/src/Workspaces/CoreTest/TestCompositionTests.cs @@ -28,11 +28,11 @@ public void Assemblies() var composition1 = TestComposition.Empty; var composition2 = composition1.AddAssemblies(assembly1); - AssertEx.SetEqual(new[] { assembly1 }, composition2.Assemblies); + AssertEx.SetEqual([assembly1], composition2.Assemblies); Assert.Empty(composition2.RemoveAssemblies(assembly1).Assemblies); var composition3 = composition2.WithAssemblies([assembly2]); - AssertEx.SetEqual(new[] { assembly2 }, composition3.Assemblies); + AssertEx.SetEqual([assembly2], composition3.Assemblies); } [Fact] @@ -45,12 +45,12 @@ public void Parts() var composition2 = composition1.AddParts(type1); var composition3 = composition2.RemoveParts(type1); - AssertEx.SetEqual(new[] { type1 }, composition2.Parts); + AssertEx.SetEqual([type1], composition2.Parts); Assert.Empty(composition3.Parts); Assert.Empty(composition3.ExcludedPartTypes); var composition4 = composition2.WithParts([type2]); - AssertEx.SetEqual(new[] { type2 }, composition4.Parts); + AssertEx.SetEqual([type2], composition4.Parts); Assert.Empty(composition3.ExcludedPartTypes); } @@ -64,14 +64,14 @@ public void ExcludedPartTypes() var composition2 = composition1.AddExcludedPartTypes(type1); var composition3 = composition2.RemoveExcludedPartTypes(type1); - AssertEx.SetEqual(new[] { type1 }, composition2.ExcludedPartTypes); + AssertEx.SetEqual([type1], composition2.ExcludedPartTypes); Assert.Empty(composition3.Parts); Assert.Empty(composition3.ExcludedPartTypes); Assert.Empty(composition3.Parts); var composition4 = composition2.WithExcludedPartTypes([type2]); - AssertEx.SetEqual(new[] { type2 }, composition4.ExcludedPartTypes); + AssertEx.SetEqual([type2], composition4.ExcludedPartTypes); Assert.Empty(composition4.Parts); } @@ -89,15 +89,15 @@ public void Composition() var composition2 = TestComposition.Empty.AddAssemblies(assembly2).AddParts(type1, type2).AddExcludedPartTypes(excluded2); var composition3 = composition1.Add(composition2); - AssertEx.SetEqual(new[] { assembly1, assembly2 }, composition3.Assemblies); - AssertEx.SetEqual(new[] { type1, type2 }, composition3.Parts); - AssertEx.SetEqual(new[] { excluded1, excluded2 }, composition3.ExcludedPartTypes); + AssertEx.SetEqual([assembly1, assembly2], composition3.Assemblies); + AssertEx.SetEqual([type1, type2], composition3.Parts); + AssertEx.SetEqual([excluded1, excluded2], composition3.ExcludedPartTypes); var composition4 = composition3.Remove(composition1); - AssertEx.SetEqual(new[] { assembly2 }, composition4.Assemblies); - AssertEx.SetEqual(new[] { type2 }, composition4.Parts); - AssertEx.SetEqual(new[] { excluded2 }, composition4.ExcludedPartTypes); + AssertEx.SetEqual([assembly2], composition4.Assemblies); + AssertEx.SetEqual([type2], composition4.Parts); + AssertEx.SetEqual([excluded2], composition4.ExcludedPartTypes); } } } diff --git a/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentIdTests.cs b/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentIdTests.cs index 178e4103dc398..038116e0aad1d 100644 --- a/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentIdTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/DocumentationCommentIdTests.cs @@ -17,7 +17,7 @@ public partial class DocumentationCommentIdTests : TestBase private static CSharpCompilation CreateCSharpCompilation(string sourceText) { var syntaxTree = SyntaxFactory.ParseSyntaxTree(sourceText); - return CSharpCompilation.Create("goo.exe").AddReferences(TestMetadata.Net451.mscorlib).AddSyntaxTrees(syntaxTree); + return CSharpCompilation.Create("goo.exe").AddReferences(NetFramework.mscorlib).AddSyntaxTrees(syntaxTree); } private static void CheckDeclarationId(string expectedId, INamespaceOrTypeSymbol symbol, Compilation compilation) diff --git a/src/Workspaces/CoreTest/UtilityTest/IntervalTreeTests.cs b/src/Workspaces/CoreTest/UtilityTest/IntervalTreeTests.cs index 24fb4d6a31594..e34f781dfead6 100644 --- a/src/Workspaces/CoreTest/UtilityTest/IntervalTreeTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/IntervalTreeTests.cs @@ -270,43 +270,43 @@ private static MutableIntervalTree CreateIntTree(params int[] values) [Fact] public void TestSortedEnumerable1() { - Assert.Equal(CreateIntTree(0, 0, 0), new[] { 0, 0, 0 }); - Assert.Equal(CreateIntTree(0, 0, 1), new[] { 0, 0, 1 }); - Assert.Equal(CreateIntTree(0, 0, 2), new[] { 0, 0, 2 }); - Assert.Equal(CreateIntTree(0, 1, 0), new[] { 0, 0, 1 }); - Assert.Equal(CreateIntTree(0, 1, 1), new[] { 0, 1, 1 }); - Assert.Equal(CreateIntTree(0, 1, 2), new[] { 0, 1, 2 }); - Assert.Equal(CreateIntTree(0, 2, 0), new[] { 0, 0, 2 }); - Assert.Equal(CreateIntTree(0, 2, 1), new[] { 0, 1, 2 }); - Assert.Equal(CreateIntTree(0, 2, 2), new[] { 0, 2, 2 }); - - Assert.Equal(CreateIntTree(1, 0, 0), new[] { 0, 0, 1 }); - Assert.Equal(CreateIntTree(1, 0, 1), new[] { 0, 1, 1 }); - Assert.Equal(CreateIntTree(1, 0, 2), new[] { 0, 1, 2 }); - Assert.Equal(CreateIntTree(1, 1, 0), new[] { 0, 1, 1 }); - Assert.Equal(CreateIntTree(1, 1, 1), new[] { 1, 1, 1 }); - Assert.Equal(CreateIntTree(1, 1, 2), new[] { 1, 1, 2 }); - Assert.Equal(CreateIntTree(1, 2, 0), new[] { 0, 1, 2 }); - Assert.Equal(CreateIntTree(1, 2, 1), new[] { 1, 1, 2 }); - Assert.Equal(CreateIntTree(1, 2, 2), new[] { 1, 2, 2 }); - - Assert.Equal(CreateIntTree(2, 0, 0), new[] { 0, 0, 2 }); - Assert.Equal(CreateIntTree(2, 0, 1), new[] { 0, 1, 2 }); - Assert.Equal(CreateIntTree(2, 0, 2), new[] { 0, 2, 2 }); - Assert.Equal(CreateIntTree(2, 1, 0), new[] { 0, 1, 2 }); - Assert.Equal(CreateIntTree(2, 1, 1), new[] { 1, 1, 2 }); - Assert.Equal(CreateIntTree(2, 1, 2), new[] { 1, 2, 2 }); - Assert.Equal(CreateIntTree(2, 2, 0), new[] { 0, 2, 2 }); - Assert.Equal(CreateIntTree(2, 2, 1), new[] { 1, 2, 2 }); - Assert.Equal(CreateIntTree(2, 2, 2), new[] { 2, 2, 2 }); + Assert.Equal(CreateIntTree(0, 0, 0), [0, 0, 0]); + Assert.Equal(CreateIntTree(0, 0, 1), [0, 0, 1]); + Assert.Equal(CreateIntTree(0, 0, 2), [0, 0, 2]); + Assert.Equal(CreateIntTree(0, 1, 0), [0, 0, 1]); + Assert.Equal(CreateIntTree(0, 1, 1), [0, 1, 1]); + Assert.Equal(CreateIntTree(0, 1, 2), [0, 1, 2]); + Assert.Equal(CreateIntTree(0, 2, 0), [0, 0, 2]); + Assert.Equal(CreateIntTree(0, 2, 1), [0, 1, 2]); + Assert.Equal(CreateIntTree(0, 2, 2), [0, 2, 2]); + + Assert.Equal(CreateIntTree(1, 0, 0), [0, 0, 1]); + Assert.Equal(CreateIntTree(1, 0, 1), [0, 1, 1]); + Assert.Equal(CreateIntTree(1, 0, 2), [0, 1, 2]); + Assert.Equal(CreateIntTree(1, 1, 0), [0, 1, 1]); + Assert.Equal(CreateIntTree(1, 1, 1), [1, 1, 1]); + Assert.Equal(CreateIntTree(1, 1, 2), [1, 1, 2]); + Assert.Equal(CreateIntTree(1, 2, 0), [0, 1, 2]); + Assert.Equal(CreateIntTree(1, 2, 1), [1, 1, 2]); + Assert.Equal(CreateIntTree(1, 2, 2), [1, 2, 2]); + + Assert.Equal(CreateIntTree(2, 0, 0), [0, 0, 2]); + Assert.Equal(CreateIntTree(2, 0, 1), [0, 1, 2]); + Assert.Equal(CreateIntTree(2, 0, 2), [0, 2, 2]); + Assert.Equal(CreateIntTree(2, 1, 0), [0, 1, 2]); + Assert.Equal(CreateIntTree(2, 1, 1), [1, 1, 2]); + Assert.Equal(CreateIntTree(2, 1, 2), [1, 2, 2]); + Assert.Equal(CreateIntTree(2, 2, 0), [0, 2, 2]); + Assert.Equal(CreateIntTree(2, 2, 1), [1, 2, 2]); + Assert.Equal(CreateIntTree(2, 2, 2), [2, 2, 2]); } [Fact] public void TestSortedEnumerable2() { - var tree = MutableIntervalTree.Create(new Int32Introspector(), new[] { 1, 0 }); + var tree = MutableIntervalTree.Create(new Int32Introspector(), [1, 0]); - Assert.Equal(tree, new[] { 0, 1 }); + Assert.Equal(tree, [0, 1]); } private void TestOverlapsAndIntersects(IList> spans) diff --git a/src/Workspaces/CoreTest/UtilityTest/NameGeneratorTests.cs b/src/Workspaces/CoreTest/UtilityTest/NameGeneratorTests.cs index 96610a53a0bbc..711561fa13d48 100644 --- a/src/Workspaces/CoreTest/UtilityTest/NameGeneratorTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/NameGeneratorTests.cs @@ -96,10 +96,10 @@ public void EnsureUniquenessInPlaceCanUseNotIncludingFirst10(string[] names, str private static void VerifyEnsureUniquenessInPlace(string[] names, bool[]? isFixed, Func? canUse, bool isCaseSensitive, string[] expectedResult) { - var namesBuilder = new ArrayBuilder(); + using var _1 = ArrayBuilder.GetInstance(out var namesBuilder); namesBuilder.AddRange(names); - var isFixedBuilder = new ArrayBuilder(); + using var _2 = ArrayBuilder.GetInstance(out var isFixedBuilder); isFixedBuilder.AddRange(isFixed ?? Enumerable.Repeat(false, names.Length)); NameGenerator.EnsureUniquenessInPlace(namesBuilder, isFixedBuilder, canUse, isCaseSensitive); diff --git a/src/Workspaces/CoreTest/UtilityTest/SpecializedTasksTests.cs b/src/Workspaces/CoreTest/UtilityTest/SpecializedTasksTests.cs index 4f2f914fe615c..b044955cb63ff 100644 --- a/src/Workspaces/CoreTest/UtilityTest/SpecializedTasksTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/SpecializedTasksTests.cs @@ -42,7 +42,7 @@ public void WhenAll_Empty() [Fact] public void WhenAll_AllCompletedSuccessfully() { - var whenAll = SpecializedTasks.WhenAll(new[] { new ValueTask(0), new ValueTask(1) }); + var whenAll = SpecializedTasks.WhenAll([new ValueTask(0), new ValueTask(1)]); Debug.Assert(whenAll.IsCompleted); Assert.True(whenAll.IsCompletedSuccessfully); Assert.Equal([0, 1], whenAll.Result); @@ -51,7 +51,7 @@ public void WhenAll_AllCompletedSuccessfully() [Fact] public void WhenAll_CompletedButCanceled() { - var whenAll = SpecializedTasks.WhenAll(new[] { new ValueTask(Task.FromCanceled(new CancellationToken(true))) }); + var whenAll = SpecializedTasks.WhenAll([new ValueTask(Task.FromCanceled(new CancellationToken(true)))]); Assert.True(whenAll.IsCompleted); Assert.False(whenAll.IsCompletedSuccessfully); Assert.ThrowsAsync(async () => await whenAll); @@ -61,7 +61,7 @@ public void WhenAll_CompletedButCanceled() public void WhenAll_NotYetCompleted() { var completionSource = new TaskCompletionSource(); - var whenAll = SpecializedTasks.WhenAll(new[] { new ValueTask(completionSource.Task) }); + var whenAll = SpecializedTasks.WhenAll([new ValueTask(completionSource.Task)]); Assert.False(whenAll.IsCompleted); completionSource.SetResult(0); Assert.True(whenAll.IsCompleted); diff --git a/src/Workspaces/CoreTest/UtilityTest/XmlDocumentationProviderTests.cs b/src/Workspaces/CoreTest/UtilityTest/XmlDocumentationProviderTests.cs index bee9663e3932e..d31a135429e6f 100644 --- a/src/Workspaces/CoreTest/UtilityTest/XmlDocumentationProviderTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/XmlDocumentationProviderTests.cs @@ -35,7 +35,7 @@ Represents a non source code file. """)); var portableExecutableReference = MetadataReference.CreateFromFile(roslynCompilersLocation, documentation: documentationProvider); - var compilation = CSharpCompilation.Create(nameof(XmlDocumentationProviderReturnsEntireMemberNode), references: new[] { portableExecutableReference }); + var compilation = CSharpCompilation.Create(nameof(XmlDocumentationProviderReturnsEntireMemberNode), references: [portableExecutableReference]); // Verify we can parse it and it contains a single node var xml = compilation.GetTypeByMetadataName("Microsoft.CodeAnalysis.AdditionalTextFile")!.GetDocumentationCommentXml(); diff --git a/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs b/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs index de93bf525780d..5e37a6187cde0 100644 --- a/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs +++ b/src/Workspaces/CoreTest/WorkspaceServiceTests/GlobalOptionServiceTests.cs @@ -186,11 +186,11 @@ public void GlobalOptions() KeyValuePairUtil.Create(new OptionKey2(option3), (object?)3), ]); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "test_option1=5", "test_option2=6", - }, events.Single().ChangedOptions.Select(e => $"{e.key.Option.Definition.ConfigName}={e.newValue}")); + ], events.Single().ChangedOptions.Select(e => $"{e.key.Option.Definition.ConfigName}={e.newValue}")); values = globalOptions.GetOptions([new OptionKey2(option1), new OptionKey2(option2), new OptionKey2(option3)]); Assert.Equal(5, values[0]); diff --git a/src/Workspaces/CoreTest/WorkspaceServiceTests/TemporaryStorageServiceTests.cs b/src/Workspaces/CoreTest/WorkspaceServiceTests/TemporaryStorageServiceTests.cs index 61adf79b57854..fa8d099d836dc 100644 --- a/src/Workspaces/CoreTest/WorkspaceServiceTests/TemporaryStorageServiceTests.cs +++ b/src/Workspaces/CoreTest/WorkspaceServiceTests/TemporaryStorageServiceTests.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.UnitTests using static TemporaryStorageService; [UseExportProvider] -#if NETCOREAPP +#if NET [SupportedOSPlatform("windows")] #endif [Trait(Traits.Feature, Traits.Features.Workspace)] @@ -60,9 +60,9 @@ public void TestTemporaryStorageStream() data.WriteByte((byte)(i % 2)); } - var handle = service.WriteToTemporaryStorage(data, CancellationToken.None); + var handle = service.WriteToTemporaryStorage(data); - using var result = handle.ReadFromTemporaryStorage(CancellationToken.None); + using var result = handle.ReadFromTemporaryStorage(); Assert.Equal(data.Length, result.Length); for (var i = 0; i < SharedPools.ByteBufferSize; i++) @@ -95,10 +95,10 @@ public void TestZeroLengthStreams() TemporaryStorageStreamHandle handle; using (var stream1 = new MemoryStream()) { - handle = service.WriteToTemporaryStorage(stream1, CancellationToken.None); + handle = service.WriteToTemporaryStorage(stream1); } - using var stream2 = handle.ReadFromTemporaryStorage(CancellationToken.None); + using var stream2 = handle.ReadFromTemporaryStorage(); Assert.Equal(0, stream2.Length); } @@ -119,15 +119,15 @@ public void TestTemporaryStorageMemoryMappedFileManagement() { for (var j = 1; j < 5; j++) { - var handle1 = service.WriteToTemporaryStorage(new MemoryStream(buffer.GetBuffer(), 0, 1024 * i - 1), CancellationToken.None); - var handle2 = service.WriteToTemporaryStorage(new MemoryStream(buffer.GetBuffer(), 0, 1024 * i), CancellationToken.None); - var handle3 = service.WriteToTemporaryStorage(new MemoryStream(buffer.GetBuffer(), 0, 1024 * i + 1), CancellationToken.None); + var handle1 = service.WriteToTemporaryStorage(new MemoryStream(buffer.GetBuffer(), 0, 1024 * i - 1)); + var handle2 = service.WriteToTemporaryStorage(new MemoryStream(buffer.GetBuffer(), 0, 1024 * i)); + var handle3 = service.WriteToTemporaryStorage(new MemoryStream(buffer.GetBuffer(), 0, 1024 * i + 1)); await Task.Yield(); - using var s1 = handle1.ReadFromTemporaryStorage(CancellationToken.None); - using var s2 = handle2.ReadFromTemporaryStorage(CancellationToken.None); - using var s3 = handle3.ReadFromTemporaryStorage(CancellationToken.None); + using var s1 = handle1.ReadFromTemporaryStorage(); + using var s2 = handle2.ReadFromTemporaryStorage(); + using var s3 = handle3.ReadFromTemporaryStorage(); Assert.Equal(1024 * i - 1, s1.Length); Assert.Equal(1024 * i, s2.Length); Assert.Equal(1024 * i + 1, s3.Length); @@ -162,13 +162,13 @@ public void TestTemporaryStorageScaling() var storageHandles = new List(fileCount); for (var i = 0; i < fileCount; i++) { - var handle = service.WriteToTemporaryStorage(data, CancellationToken.None); + var handle = service.WriteToTemporaryStorage(data); storageHandles.Add(handle); } for (var i = 0; i < 1024 * 5; i++) { - using var s = storageHandles[i].ReadFromTemporaryStorage(CancellationToken.None); + using var s = storageHandles[i].ReadFromTemporaryStorage(); Assert.Equal(1, s.ReadByte()); } } @@ -187,10 +187,10 @@ public void StreamTest1() expected.WriteByte((byte)(i % byte.MaxValue)); } - var handle = service.WriteToTemporaryStorage(expected, CancellationToken.None); + var handle = service.WriteToTemporaryStorage(expected); expected.Position = 0; - using var stream = handle.ReadFromTemporaryStorage(CancellationToken.None); + using var stream = handle.ReadFromTemporaryStorage(); Assert.Equal(expected.Length, stream.Length); for (var i = 0; i < expected.Length; i++) @@ -212,10 +212,10 @@ public void StreamTest2() expected.WriteByte((byte)(i % byte.MaxValue)); } - var handle = service.WriteToTemporaryStorage(expected, CancellationToken.None); + var handle = service.WriteToTemporaryStorage(expected); expected.Position = 0; - using var stream = handle.ReadFromTemporaryStorage(CancellationToken.None); + using var stream = handle.ReadFromTemporaryStorage(); Assert.Equal(expected.Length, stream.Length); var index = 0; @@ -252,10 +252,10 @@ public void StreamTest3() expected.WriteByte(value); } - var handle = service.WriteToTemporaryStorage(expected, CancellationToken.None); + var handle = service.WriteToTemporaryStorage(expected); expected.Position = 0; - using var stream = handle.ReadFromTemporaryStorage(CancellationToken.None); + using var stream = handle.ReadFromTemporaryStorage(); Assert.Equal(expected.Length, stream.Length); for (var i = 0; i < expected.Length; i++) diff --git a/src/Workspaces/CoreTest/WorkspaceTests/AdhocWorkspaceTests.cs b/src/Workspaces/CoreTest/WorkspaceTests/AdhocWorkspaceTests.cs index 6cd4c04aa30f3..f5983c639e8ec 100644 --- a/src/Workspaces/CoreTest/WorkspaceTests/AdhocWorkspaceTests.cs +++ b/src/Workspaces/CoreTest/WorkspaceTests/AdhocWorkspaceTests.cs @@ -87,7 +87,7 @@ public void TestAddSolution_SolutionInfo() assemblyName: "TestProject.dll", language: LanguageNames.CSharp); - var sinfo = SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Default, projects: new ProjectInfo[] { pinfo }); + var sinfo = SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Default, projects: [pinfo]); var solution = ws.AddSolution(sinfo); diff --git a/src/Workspaces/CoreTest/WorkspaceTests/WorkspaceTests.cs b/src/Workspaces/CoreTest/WorkspaceTests/WorkspaceTests.cs index 5c83142a53225..f5d41bb8bcae7 100644 --- a/src/Workspaces/CoreTest/WorkspaceTests/WorkspaceTests.cs +++ b/src/Workspaces/CoreTest/WorkspaceTests/WorkspaceTests.cs @@ -103,7 +103,7 @@ public void WithAnalyzerReferences_TryApplyChanges_Throws() using var ws = new NoChangesAllowedWorkspace(); var projectId = ws.AddProject("TestProject", LanguageNames.CSharp).Id; - var newSolution = ws.CurrentSolution.WithAnalyzerReferences(new[] { new TestAnalyzerReference() }); + var newSolution = ws.CurrentSolution.WithAnalyzerReferences([new TestAnalyzerReference()]); Assert.Equal(WorkspacesResources.Adding_analyzer_references_is_not_supported, Assert.Throws(() => ws.TryApplyChanges(newSolution)).Message); diff --git a/src/Workspaces/CoreTestUtilities/MEF/ExportProviderCache.cs b/src/Workspaces/CoreTestUtilities/MEF/ExportProviderCache.cs index 218ad89f52e48..27ea6072c28ac 100644 --- a/src/Workspaces/CoreTestUtilities/MEF/ExportProviderCache.cs +++ b/src/Workspaces/CoreTestUtilities/MEF/ExportProviderCache.cs @@ -24,21 +24,18 @@ public static class ExportProviderCache private static readonly TestComposition s_defaultHostExportProviderComposition = TestComposition.Empty .AddAssemblies(MefHostServices.DefaultAssemblies) .AddParts(typeof(TestSerializerService.Factory)); - - private static bool _enabled; - private static readonly Scope _localCompositionScope = new Scope("local"); private static readonly Scope _remoteCompositionScope = new Scope("remote"); - internal static bool Enabled => _enabled; + internal static bool Enabled { get; private set; } internal static ExportProvider? LocalExportProviderForCleanup => _localCompositionScope.CurrentExportProvider; internal static ExportProvider? RemoteExportProviderForCleanup => _remoteCompositionScope.CurrentExportProvider; internal static void SetEnabled_OnlyUseExportProviderAttributeCanCall(bool value) { - _enabled = value; - if (!_enabled) + Enabled = value; + if (!Enabled) { _localCompositionScope.Clear(); _remoteCompositionScope.Clear(); diff --git a/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs b/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs index 984cac85ea590..f270b5f81590b 100644 --- a/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs +++ b/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs @@ -198,6 +198,7 @@ public InProcRemoteServices(SolutionServices workspaceServices, TraceListener? t RegisterRemoteBrokeredService(new RemoteNavigateToSearchService.Factory()); RegisterRemoteBrokeredService(new RemoteNavigationBarItemService.Factory()); RegisterRemoteBrokeredService(new RemoteProcessTelemetryService.Factory()); + RegisterRemoteBrokeredService(new RemoteRelatedDocumentsService.Factory()); RegisterRemoteBrokeredService(new RemoteRenamerService.Factory()); RegisterRemoteBrokeredService(new RemoteSemanticClassificationService.Factory()); RegisterRemoteBrokeredService(new RemoteSemanticSearchService.Factory()); @@ -303,7 +304,7 @@ public override int WriteTimeout public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => _stream.ReadAsync(buffer, offset, count, cancellationToken); public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => _stream.WriteAsync(buffer, offset, count, cancellationToken); -#if NETCOREAPP // nullability annotations differ +#if NET // nullability annotations differ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => _stream.BeginRead(buffer, offset, count, callback, state); public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => _stream.BeginWrite(buffer, offset, count, callback, state); #else diff --git a/src/Workspaces/CoreTestUtilities/Remote/InProcRemoteHostClientProvider.cs b/src/Workspaces/CoreTestUtilities/Remote/InProcRemoteHostClientProvider.cs index e216af1473e25..f9282729fe3e5 100644 --- a/src/Workspaces/CoreTestUtilities/Remote/InProcRemoteHostClientProvider.cs +++ b/src/Workspaces/CoreTestUtilities/Remote/InProcRemoteHostClientProvider.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.UnitTests.Remote; +using Microsoft.VisualStudio.Threading; using Roslyn.Test.Utilities; namespace Microsoft.CodeAnalysis.Remote.Testing @@ -62,6 +63,7 @@ private static RemoteWorkspace CreateRemoteWorkspace( private readonly SolutionServices _services; private readonly Lazy _lazyManager; private readonly Lazy _lazyClient; + private readonly TaskCompletionSource _clientCreationSource = new(); public Type[]? AdditionalRemoteParts { get; set; } public Type[]? ExcludedRemoteParts { get; set; } @@ -80,11 +82,21 @@ public InProcRemoteHostClientProvider(SolutionServices services, RemoteServiceCa AdditionalRemoteParts, ExcludedRemoteParts)); _lazyClient = new Lazy( - () => InProcRemoteHostClient.Create( - _services, - callbackDispatchers, - TraceListener, - new RemoteHostTestData(_lazyManager.Value, isInProc: true))); + () => + { + try + { + return InProcRemoteHostClient.Create( + _services, + callbackDispatchers, + TraceListener, + new RemoteHostTestData(_lazyManager.Value, isInProc: true)); + } + finally + { + _clientCreationSource.SetResult(true); + } + }); } public void Dispose() @@ -99,6 +111,9 @@ public void Dispose() public Task TryGetRemoteHostClientAsync(CancellationToken cancellationToken) => Task.FromResult(_lazyClient.Value); + + public Task WaitForClientCreationAsync(CancellationToken cancellationToken) + => _clientCreationSource.Task.WithCancellation(cancellationToken); } #pragma warning restore CA1416 // Validate platform compatibility } diff --git a/src/Workspaces/CoreTestUtilities/Remote/TestSerializerService.cs b/src/Workspaces/CoreTestUtilities/Remote/TestSerializerService.cs index 3ce81ef9f9c1c..b0dedbca1e427 100644 --- a/src/Workspaces/CoreTestUtilities/Remote/TestSerializerService.cs +++ b/src/Workspaces/CoreTestUtilities/Remote/TestSerializerService.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; @@ -11,7 +9,7 @@ using System.Composition; using System.Linq; using System.Runtime.Versioning; -using System.Threading; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; @@ -24,30 +22,27 @@ namespace Microsoft.CodeAnalysis.UnitTests.Remote { -#if NETCOREAPP +#if NET [SupportedOSPlatform("windows")] #endif - internal sealed class TestSerializerService : SerializerService + [method: Obsolete(MefConstruction.FactoryMethodMessage, error: true)] + internal sealed class TestSerializerService( + ConcurrentDictionary sharedTestGeneratorReferences, + SolutionServices workspaceServices) + : SerializerService(workspaceServices) { - private static readonly ImmutableDictionary s_wellKnownReferenceNames = ImmutableDictionary.Create(ReferenceEqualityComparer.Instance) + private static readonly ImmutableDictionary s_wellKnownReferenceNames = ImmutableDictionary.Create(ReferenceEqualityComparer.Instance) .Add(TestBase.MscorlibRef_v46, nameof(TestBase.MscorlibRef_v46)) .Add(TestBase.SystemRef_v46, nameof(TestBase.SystemRef_v46)) .Add(TestBase.SystemCoreRef_v46, nameof(TestBase.SystemCoreRef_v46)) .Add(TestBase.ValueTupleRef, nameof(TestBase.ValueTupleRef)) .Add(TestBase.SystemRuntimeFacadeRef, nameof(TestBase.SystemRuntimeFacadeRef)); private static readonly ImmutableDictionary s_wellKnownReferences = ImmutableDictionary.Create() - .AddRange(s_wellKnownReferenceNames.Select(pair => KeyValuePairUtil.Create(pair.Value, pair.Key))); - - private readonly ConcurrentDictionary _sharedTestGeneratorReferences; + .AddRange(s_wellKnownReferenceNames.Select(pair => KeyValuePairUtil.Create(pair.Value!, pair.Key))); - [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] - public TestSerializerService(ConcurrentDictionary sharedTestGeneratorReferences, SolutionServices workspaceServices) - : base(workspaceServices) - { - _sharedTestGeneratorReferences = sharedTestGeneratorReferences; - } + private readonly ConcurrentDictionary _sharedTestGeneratorReferences = sharedTestGeneratorReferences; - public override void WriteMetadataReferenceTo(MetadataReference reference, ObjectWriter writer, CancellationToken cancellationToken) + protected override void WriteMetadataReferenceTo(MetadataReference reference, ObjectWriter writer) { var wellKnownReferenceName = s_wellKnownReferenceNames.GetValueOrDefault(reference, null); if (wellKnownReferenceName is not null) @@ -58,24 +53,21 @@ public override void WriteMetadataReferenceTo(MetadataReference reference, Objec else { writer.WriteBoolean(false); - base.WriteMetadataReferenceTo(reference, writer, cancellationToken); + base.WriteMetadataReferenceTo(reference, writer); } } - public override MetadataReference ReadMetadataReferenceFrom(ObjectReader reader, CancellationToken cancellationToken) - { - if (reader.ReadBoolean()) - { - // this is a well-known reference - return s_wellKnownReferences[reader.ReadString()]; - } - else - { - return base.ReadMetadataReferenceFrom(reader, cancellationToken); - } - } + protected override MetadataReference ReadMetadataReferenceFrom(ObjectReader reader) + => reader.ReadBoolean() + ? s_wellKnownReferences[reader.ReadRequiredString()] + : base.ReadMetadataReferenceFrom(reader); + + protected override Checksum CreateChecksum(AnalyzerReference reference) + => reference is TestGeneratorReference generatorReference + ? generatorReference.Checksum + : base.CreateChecksum(reference); - public override void WriteAnalyzerReferenceTo(AnalyzerReference reference, ObjectWriter writer, CancellationToken cancellationToken) + protected override void WriteAnalyzerReferenceTo(AnalyzerReference reference, ObjectWriter writer) { if (reference is TestGeneratorReference generatorReference) { @@ -86,11 +78,11 @@ public override void WriteAnalyzerReferenceTo(AnalyzerReference reference, Objec else { writer.WriteGuid(Guid.Empty); - base.WriteAnalyzerReferenceTo(reference, writer, cancellationToken); + base.WriteAnalyzerReferenceTo(reference, writer); } } - public override AnalyzerReference ReadAnalyzerReferenceFrom(ObjectReader reader, CancellationToken cancellationToken) + protected override AnalyzerReference ReadAnalyzerReferenceFrom(ObjectReader reader) { var testGeneratorReferenceGuid = reader.ReadGuid(); @@ -101,20 +93,22 @@ public override AnalyzerReference ReadAnalyzerReferenceFrom(ObjectReader reader, } else { - return base.ReadAnalyzerReferenceFrom(reader, cancellationToken); + return base.ReadAnalyzerReferenceFrom(reader); } } [ExportWorkspaceServiceFactory(typeof(ISerializerService), layer: ServiceLayer.Test), Shared, PartNotDiscoverable] [Export(typeof(Factory))] - internal new sealed class Factory : IWorkspaceServiceFactory + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + internal new sealed class Factory() : IWorkspaceServiceFactory { - private ConcurrentDictionary _sharedTestGeneratorReferences; + private ConcurrentDictionary? _sharedTestGeneratorReferences; /// /// Gate to serialize reads/writes to . /// - private readonly object _gate = new object(); + private readonly object _gate = new(); /// /// In unit tests that are testing OOP, we want to be able to share test generator references directly @@ -150,12 +144,6 @@ public ConcurrentDictionary SharedTestGeneratorRef } } - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public Factory() - { - } - [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) => new TestSerializerService(SharedTestGeneratorReferences, workspaceServices.SolutionServices); diff --git a/src/Workspaces/CoreTestUtilities/TestGeneratorReference.cs b/src/Workspaces/CoreTestUtilities/TestGeneratorReference.cs index 7628db6971281..1ac9fdbce650d 100644 --- a/src/Workspaces/CoreTestUtilities/TestGeneratorReference.cs +++ b/src/Workspaces/CoreTestUtilities/TestGeneratorReference.cs @@ -13,10 +13,10 @@ namespace Roslyn.Test.Utilities /// A simple deriviation of that returns the source generator /// passed, for ease in unit tests. /// - public class TestGeneratorReference : AnalyzerReference, IChecksummedObject + public class TestGeneratorReference : AnalyzerReference { private readonly ISourceGenerator _generator; - private readonly Checksum _checksum; + internal readonly Checksum Checksum; public TestGeneratorReference(ISourceGenerator generator, string? analyzerFilePath = null) { @@ -30,7 +30,7 @@ public TestGeneratorReference(ISourceGenerator generator, string? analyzerFilePa // We'll make up a checksum here so we can "serialize" it to our unit test in-proc "remote" host. var checksumArray = Guid.ToByteArray(); Array.Resize(ref checksumArray, Checksum.HashSize); - _checksum = Checksum.From(checksumArray); + this.Checksum = Checksum.From(checksumArray); FullPath = analyzerFilePath; } @@ -44,8 +44,6 @@ public TestGeneratorReference(IIncrementalGenerator generator, string? analyzerF public override object Id => this; public Guid Guid { get; } - Checksum IChecksummedObject.Checksum => _checksum; - public override ImmutableArray GetAnalyzers(string language) => []; public override ImmutableArray GetAnalyzersForAllLanguages() => []; public override ImmutableArray GetGenerators(string language) => [_generator]; diff --git a/src/Workspaces/CoreTestUtilities/Workspaces/TestHostProject`1.cs b/src/Workspaces/CoreTestUtilities/Workspaces/TestHostProject`1.cs index fec56bbef4c6b..f2df12d8dd1c8 100644 --- a/src/Workspaces/CoreTestUtilities/Workspaces/TestHostProject`1.cs +++ b/src/Workspaces/CoreTestUtilities/Workspaces/TestHostProject`1.cs @@ -23,22 +23,14 @@ public abstract class TestHostProject : AbstractTestHostProject private readonly ProjectId _id; private readonly string _name; - private readonly IEnumerable _metadataReferences; private readonly IEnumerable _analyzerReferences; - private readonly CompilationOptions _compilationOptions; - private readonly ParseOptions _parseOptions; - private readonly bool _isSubmission; private readonly string _assemblyName; - private readonly Type _hostObjectType; - private readonly VersionStamp _version; - private readonly string _outputFilePath; private readonly string _defaultNamespace; public IEnumerable Documents; public IEnumerable AdditionalDocuments; public IEnumerable AnalyzerConfigDocuments; public IEnumerable ProjectReferences; - private string _filePath; public override string Name { @@ -48,13 +40,7 @@ public override string Name } } - public IEnumerable MetadataReferences - { - get - { - return _metadataReferences; - } - } + public IEnumerable MetadataReferences { get; } public IEnumerable AnalyzerReferences { @@ -64,21 +50,9 @@ public IEnumerable AnalyzerReferences } } - public CompilationOptions CompilationOptions - { - get - { - return _compilationOptions; - } - } + public CompilationOptions CompilationOptions { get; } - public ParseOptions ParseOptions - { - get - { - return _parseOptions; - } - } + public ParseOptions ParseOptions { get; } public override ProjectId Id { @@ -88,13 +62,7 @@ public override ProjectId Id } } - public bool IsSubmission - { - get - { - return _isSubmission; - } - } + public bool IsSubmission { get; } public override string AssemblyName { @@ -104,37 +72,16 @@ public override string AssemblyName } } - public Type HostObjectType - { - get - { - return _hostObjectType; - } - } + public Type HostObjectType { get; } - public VersionStamp Version - { - get - { - return _version; - } - } + public VersionStamp Version { get; } - public string FilePath - { - get - { - return _filePath; - } - } + public string FilePath { get; private set; } internal void OnProjectFilePathChanged(string filePath) - => _filePath = filePath; + => FilePath = filePath; - public string OutputFilePath - { - get { return _outputFilePath; } - } + public string OutputFilePath { get; } public string DefaultNamespace { @@ -161,19 +108,19 @@ protected TestHostProject( _name = projectName; _id = ProjectId.CreateNewId(debugName: this.AssemblyName); _languageServices = languageServices; - _compilationOptions = compilationOptions; - _parseOptions = parseOptions; - _metadataReferences = references; + CompilationOptions = compilationOptions; + ParseOptions = parseOptions; + MetadataReferences = references; _analyzerReferences = analyzerReferences ?? SpecializedCollections.EmptyEnumerable(); this.Documents = documents; this.AdditionalDocuments = additionalDocuments ?? SpecializedCollections.EmptyEnumerable(); this.AnalyzerConfigDocuments = analyzerConfigDocuments ?? SpecializedCollections.EmptyEnumerable(); ProjectReferences = SpecializedCollections.EmptyEnumerable(); - _isSubmission = isSubmission; - _hostObjectType = hostObjectType; - _version = VersionStamp.Create(); - _filePath = filePath; - _outputFilePath = GetTestOutputFilePath(filePath); + IsSubmission = isSubmission; + HostObjectType = hostObjectType; + Version = VersionStamp.Create(); + FilePath = filePath; + OutputFilePath = GetTestOutputFilePath(filePath); _defaultNamespace = defaultNamespace; } @@ -199,17 +146,17 @@ protected TestHostProject( language = language ?? LanguageNames.CSharp; _languageServices = hostServices.GetLanguageServices(language); - _compilationOptions = compilationOptions ?? this.LanguageServiceProvider.GetService().GetDefaultCompilationOptions(); - _parseOptions = parseOptions ?? this.LanguageServiceProvider.GetService().GetDefaultParseOptions(); + CompilationOptions = compilationOptions ?? this.LanguageServiceProvider.GetService().GetDefaultCompilationOptions(); + ParseOptions = parseOptions ?? this.LanguageServiceProvider.GetService().GetDefaultParseOptions(); this.Documents = documents ?? SpecializedCollections.EmptyEnumerable(); this.AdditionalDocuments = additionalDocuments ?? SpecializedCollections.EmptyEnumerable(); this.AnalyzerConfigDocuments = analyzerConfigDocuments ?? SpecializedCollections.EmptyEnumerable(); ProjectReferences = projectReferences != null ? projectReferences.Select(p => new ProjectReference(p.Id)) : SpecializedCollections.EmptyEnumerable(); - _metadataReferences = metadataReferences ?? new MetadataReference[] { TestMetadata.Net451.mscorlib }; + MetadataReferences = metadataReferences ?? new MetadataReference[] { NetFramework.mscorlib }; _analyzerReferences = analyzerReferences ?? SpecializedCollections.EmptyEnumerable(); _assemblyName = assemblyName ?? "TestProject"; - _version = VersionStamp.Create(); - _outputFilePath = GetTestOutputFilePath(_filePath); + Version = VersionStamp.Create(); + OutputFilePath = GetTestOutputFilePath(FilePath); _defaultNamespace = defaultNamespace; if (documents != null) diff --git a/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_Create.cs b/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_Create.cs index 6aa4958b64b4b..955651f9e0fca 100644 --- a/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_Create.cs +++ b/src/Workspaces/CoreTestUtilities/Workspaces/TestWorkspace_Create.cs @@ -46,7 +46,7 @@ internal static TestWorkspace Create( ParseOptions parseOptions, string content) { - return Create(language, compilationOptions, parseOptions, new[] { content }); + return Create(language, compilationOptions, parseOptions, [content]); } /// @@ -60,7 +60,7 @@ internal static TestWorkspace Create( ParseOptions parseOptions, string content) { - return Create(workspaceKind, language, compilationOptions, parseOptions, new[] { content }); + return Create(workspaceKind, language, compilationOptions, parseOptions, [content]); } /// Can pass in multiple file contents: files will be named test1.cs, test2.cs, etc. diff --git a/src/Workspaces/MSBuildTest/NewlyCreatedProjectsFromDotNetNew.cs b/src/Workspaces/MSBuildTest/NewlyCreatedProjectsFromDotNetNew.cs index a5255d627a011..16f379fbcfb81 100644 --- a/src/Workspaces/MSBuildTest/NewlyCreatedProjectsFromDotNetNew.cs +++ b/src/Workspaces/MSBuildTest/NewlyCreatedProjectsFromDotNetNew.cs @@ -74,7 +74,7 @@ public async Task ValidateCSharpTemplateProjects(string templateName) await AssertTemplateProjectLoadsCleanlyAsync(templateName, LanguageNames.CSharp); } - [ConditionalTheory(typeof(DotNetSdkMSBuildInstalled))] + [ConditionalTheory(typeof(DotNetSdkMSBuildInstalled), AlwaysSkip = "https://github.com/dotnet/roslyn/issues/74827")] [MemberData(nameof(GetVisualBasicProjectTemplateNames), DisableDiscoveryEnumeration = false)] public async Task ValidateVisualBasicTemplateProjects(string templateName) { @@ -109,7 +109,7 @@ public static TheoryData GetProjectTemplateNames(string language) var result = RunDotNet($"new list --type project --language {language}", output: null); - var lines = result.Output.Split(new[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); + var lines = result.Output.Split(["\r", "\n"], StringSplitOptions.RemoveEmptyEntries); TheoryData templateNames = []; var foundDivider = false; @@ -125,7 +125,7 @@ public static TheoryData GetProjectTemplateNames(string language) continue; } - var columns = line.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries) + var columns = line.Split([" "], StringSplitOptions.RemoveEmptyEntries) .Select(c => c.Trim()) .ToArray(); diff --git a/src/Workspaces/MSBuildTest/VisualStudioMSBuildWorkspaceTests.cs b/src/Workspaces/MSBuildTest/VisualStudioMSBuildWorkspaceTests.cs index ea9cf6ad02c76..8ff00ac110e18 100644 --- a/src/Workspaces/MSBuildTest/VisualStudioMSBuildWorkspaceTests.cs +++ b/src/Workspaces/MSBuildTest/VisualStudioMSBuildWorkspaceTests.cs @@ -1838,15 +1838,15 @@ public async Task TestCompilationOptions_VisualBasic_GlobalImports() var imports = options.GlobalImports; AssertEx.Equal( - expected: new[] - { - "Microsoft.VisualBasic", - "System", - "System.Collections", - "System.Collections.Generic", - "System.Diagnostics", - "System.Linq", - }, + expected: + [ + "Microsoft.VisualBasic", + "System", + "System.Collections", + "System.Collections.Generic", + "System.Diagnostics", + "System.Linq", + ], actual: imports.Select(i => i.Name)); } @@ -1865,21 +1865,21 @@ public async Task TestParseOptions_VisualBasic_PreprocessorSymbols() defines.Sort((x, y) => x.Key.CompareTo(y.Key)); AssertEx.Equal( - expected: new[] - { - new KeyValuePair("_MyType", "Windows"), - new KeyValuePair("CONFIG", "Debug"), - new KeyValuePair("DEBUG", -1), - new KeyValuePair("F", false), - new KeyValuePair("PLATFORM", "AnyCPU"), - new KeyValuePair("T", -1), - new KeyValuePair("TARGET", "library"), - new KeyValuePair("TRACE", -1), - new KeyValuePair("VBC_VER", 123), - new KeyValuePair("X", 1), - new KeyValuePair("Y", 2), - new KeyValuePair("Z", true), - }, + expected: + [ + new KeyValuePair("_MyType", "Windows"), + new KeyValuePair("CONFIG", "Debug"), + new KeyValuePair("DEBUG", -1), + new KeyValuePair("F", false), + new KeyValuePair("PLATFORM", "AnyCPU"), + new KeyValuePair("T", -1), + new KeyValuePair("TARGET", "library"), + new KeyValuePair("TRACE", -1), + new KeyValuePair("VBC_VER", 123), + new KeyValuePair("X", 1), + new KeyValuePair("Y", 2), + new KeyValuePair("Z", true), + ], actual: defines); } @@ -1900,7 +1900,7 @@ public async Task Test_VisualBasic_ConditionalAttributeEmitted() var compilation = await project.GetCompilationAsync(); var metadataBytes = compilation.EmitToArray(); var mtref = MetadataReference.CreateFromImage(metadataBytes); - var mtcomp = CS.CSharpCompilation.Create("MT", references: new MetadataReference[] { mtref }); + var mtcomp = CS.CSharpCompilation.Create("MT", references: [mtref]); var sym = (IAssemblySymbol)mtcomp.GetAssemblyOrModuleSymbol(mtref); var attrs = sym.GetAttributes(); @@ -1923,7 +1923,7 @@ public async Task Test_VisualBasic_ConditionalAttributeNotEmitted() var compilation = await project.GetCompilationAsync(); var metadataBytes = compilation.EmitToArray(); var mtref = MetadataReference.CreateFromImage(metadataBytes); - var mtcomp = CS.CSharpCompilation.Create("MT", references: new MetadataReference[] { mtref }); + var mtcomp = CS.CSharpCompilation.Create("MT", references: [mtref]); var sym = (IAssemblySymbol)mtcomp.GetAssemblyOrModuleSymbol(mtref); var attrs = sym.GetAttributes(); @@ -1947,7 +1947,7 @@ public async Task Test_CSharp_ConditionalAttributeEmitted() var compilation = await project.GetCompilationAsync(); var metadataBytes = compilation.EmitToArray(); var mtref = MetadataReference.CreateFromImage(metadataBytes); - var mtcomp = CS.CSharpCompilation.Create("MT", references: new MetadataReference[] { mtref }); + var mtcomp = CS.CSharpCompilation.Create("MT", references: [mtref]); var sym = (IAssemblySymbol)mtcomp.GetAssemblyOrModuleSymbol(mtref); var attrs = sym.GetAttributes(); @@ -1970,7 +1970,7 @@ public async Task Test_CSharp_ConditionalAttributeNotEmitted() var compilation = await project.GetCompilationAsync(); var metadataBytes = compilation.EmitToArray(); var mtref = MetadataReference.CreateFromImage(metadataBytes); - var mtcomp = CS.CSharpCompilation.Create("MT", references: new MetadataReference[] { mtref }); + var mtcomp = CS.CSharpCompilation.Create("MT", references: [mtref]); var sym = (IAssemblySymbol)mtcomp.GetAssemblyOrModuleSymbol(mtref); var attrs = sym.GetAttributes(); @@ -2012,7 +2012,7 @@ public async Task TestAddDocumentAsync() var project = solution.GetProjectsByName("CSharpProject").FirstOrDefault(); var newText = SourceText.From("public class Bar { }"); - workspace.AddDocument(project.Id, new string[] { "NewFolder" }, "Bar.cs", newText); + workspace.AddDocument(project.Id, ["NewFolder"], "Bar.cs", newText); // check workspace current solution var solution2 = workspace.CurrentSolution; @@ -3215,7 +3215,7 @@ public async Task TestDuplicateProjectAndMetadataReferences() Assert.Single(project.ProjectReferences); AssertEx.Equal( - new[] { "EmptyLibrary.dll", "System.Core.dll", "mscorlib.dll" }, + ["EmptyLibrary.dll", "System.Core.dll", "mscorlib.dll"], project.MetadataReferences.Select(r => Path.GetFileName(((PortableExecutableReference)r).FilePath)).OrderBy(StringComparer.Ordinal)); var compilation = await project.GetCompilationAsync(); diff --git a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs index 2afedfce05534..6e619039fe958 100644 --- a/src/Workspaces/Remote/Core/AbstractAssetProvider.cs +++ b/src/Workspaces/Remote/Core/AbstractAssetProvider.cs @@ -162,70 +162,3 @@ public Task GetAssetsAsync(AssetPath assetPath, ChecksumCollection checksu => assetProvider.GetAssetsAsync(assetPath, checksums, callback, arg, cancellationToken); } } - -internal static class AbstractAssetProviderExtensions -{ - public static Task GetAssetsAsync( - this AbstractAssetProvider assetProvider, AssetPath assetPath, HashSet checksums, CancellationToken cancellationToken) - { - return assetProvider.GetAssetsAsync( - assetPath, checksums, callback: null, arg: default, cancellationToken); - } - - public static Task GetAssetsAsync( - this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, CancellationToken cancellationToken) - { - return assetProvider.GetAssetsAsync( - assetPath, checksums, callback: null, arg: default, cancellationToken); - } - - public static async Task GetAssetsAsync( - this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, Action? callback, TArg? arg, CancellationToken cancellationToken) - { - using var _1 = PooledHashSet.GetInstance(out var checksumSet); -#if NET - checksumSet.EnsureCapacity(checksums.Children.Length); -#endif - checksumSet.AddAll(checksums.Children); - - await assetProvider.GetAssetsAsync(assetPath, checksumSet, callback, arg, cancellationToken).ConfigureAwait(false); - } - - /// - /// Returns an array of assets, corresponding to all the checksums found in the given . - /// The assets will be returned in the order corresponding to their checksum in . - /// - public static async Task> GetAssetsArrayAsync( - this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, CancellationToken cancellationToken) where T : class - { - // Note: nothing stops 'checksums' from having multiple identical checksums in it. First, collapse this down to - // a set so we're only asking about unique checksums. - using var _1 = PooledHashSet.GetInstance(out var checksumSet); -#if NET - checksumSet.EnsureCapacity(checksums.Children.Length); -#endif - checksumSet.AddAll(checksums.Children); - - using var _2 = PooledDictionary.GetInstance(out var checksumToAsset); - - await assetProvider.GetAssetHelper().GetAssetsAsync( - assetPath, checksumSet, - // Calling .Add here is safe. As checksum-set is a unique set of checksums, we'll never have collions here. - static (checksum, asset, checksumToAsset) => checksumToAsset.Add(checksum, asset), - checksumToAsset, - cancellationToken).ConfigureAwait(false); - - // Note: GetAssetsAsync will only succeed if we actually found all our assets (it crashes otherwise). So we can - // just safely assume we can index into checksumToAsset here. - Contract.ThrowIfTrue(checksumToAsset.Count != checksumSet.Count); - - // The result of GetAssetsArrayAsync wants the returned assets to be in the exact order of the checksums that - // were in 'checksums'. So now fetch the assets in that order, even if we found them in an entirely different - // order. - var result = new FixedSizeArrayBuilder(checksums.Children.Length); - foreach (var checksum in checksums.Children) - result.Add(checksumToAsset[checksum]); - - return result.MoveToImmutable(); - } -} diff --git a/src/Workspaces/Remote/Core/AbstractAssetProviderExtensions.cs b/src/Workspaces/Remote/Core/AbstractAssetProviderExtensions.cs new file mode 100644 index 0000000000000..b58173f4c6138 --- /dev/null +++ b/src/Workspaces/Remote/Core/AbstractAssetProviderExtensions.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.Collections.Generic; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Serialization; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Remote; + +internal static class AbstractAssetProviderExtensions +{ + public static Task GetAssetsAsync( + this AbstractAssetProvider assetProvider, AssetPath assetPath, HashSet checksums, CancellationToken cancellationToken) + { + return assetProvider.GetAssetsAsync( + assetPath, checksums, callback: null, arg: default, cancellationToken); + } + + public static Task GetAssetsAsync( + this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, CancellationToken cancellationToken) + { + return assetProvider.GetAssetsAsync( + assetPath, checksums, callback: null, arg: default, cancellationToken); + } + + public static async Task GetAssetsAsync( + this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, Action? callback, TArg? arg, CancellationToken cancellationToken) + { + using var _1 = PooledHashSet.GetInstance(out var checksumSet); +#if NET + checksumSet.EnsureCapacity(checksums.Children.Length); +#endif + checksumSet.AddAll(checksums.Children); + + await assetProvider.GetAssetsAsync(assetPath, checksumSet, callback, arg, cancellationToken).ConfigureAwait(false); + } + + /// + /// Returns an array of assets, corresponding to all the checksums found in the given . + /// The assets will be returned in the order corresponding to their checksum in . + /// + public static async Task> GetAssetsArrayAsync( + this AbstractAssetProvider assetProvider, AssetPath assetPath, ChecksumCollection checksums, CancellationToken cancellationToken) where T : class + { + // Note: nothing stops 'checksums' from having multiple identical checksums in it. First, collapse this down to + // a set so we're only asking about unique checksums. + using var _1 = PooledHashSet.GetInstance(out var checksumSet); +#if NET + checksumSet.EnsureCapacity(checksums.Children.Length); +#endif + checksumSet.AddAll(checksums.Children); + + using var _2 = PooledDictionary.GetInstance(out var checksumToAsset); + + await assetProvider.GetAssetHelper().GetAssetsAsync( + assetPath, checksumSet, + // Calling .Add here is safe. As checksum-set is a unique set of checksums, we'll never have collions here. + static (checksum, asset, checksumToAsset) => checksumToAsset.Add(checksum, asset), + checksumToAsset, + cancellationToken).ConfigureAwait(false); + + // Note: GetAssetsAsync will only succeed if we actually found all our assets (it crashes otherwise). So we can + // just safely assume we can index into checksumToAsset here. + Contract.ThrowIfTrue(checksumToAsset.Count != checksumSet.Count); + + // The result of GetAssetsArrayAsync wants the returned assets to be in the exact order of the checksums that + // were in 'checksums'. So now fetch the assets in that order, even if we found them in an entirely different + // order. + var result = new FixedSizeArrayBuilder(checksums.Children.Length); + foreach (var checksum in checksums.Children) + result.Add(checksumToAsset[checksum]); + + return result.MoveToImmutable(); + } +} diff --git a/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs b/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs index 0b92ff60e221e..4e5dfd34a0838 100644 --- a/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs +++ b/src/Workspaces/Remote/Core/BrokeredServiceDescriptors.cs @@ -77,6 +77,10 @@ protected override JsonRpcConnection CreateConnection(JsonRpc jsonRpc) public static readonly ServiceRpcDescriptor GenericHotReloadAgentManagerService = CreateDebuggerServiceDescriptor("GenericHotReloadAgentManagerService", new Version(0, 1)); public static readonly ServiceRpcDescriptor HotReloadOptionService = CreateDebuggerClientServiceDescriptor("HotReloadOptionService", new Version(0, 1)); public static readonly ServiceRpcDescriptor MauiLaunchCustomizerService = CreateMauiServiceDescriptor("MauiLaunchCustomizerService", new Version(0, 1)); + public static readonly ServiceRpcDescriptor DebuggerSymbolLocatorService = + CreateDebuggerServiceDescriptor("SymbolLocatorService", new Version(0, 1), new MultiplexingStream.Options { ProtocolMajorVersion = 3 }); + public static readonly ServiceRpcDescriptor DebuggerSourceLinkService = + CreateDebuggerServiceDescriptor("SourceLinkService", new Version(0, 1), new MultiplexingStream.Options { ProtocolMajorVersion = 3 }); public static ServiceMoniker CreateMoniker(string namespaceName, string componentName, string serviceName, Version? version) => new(namespaceName + "." + componentName + "." + serviceName, version); @@ -97,8 +101,8 @@ public static ServiceJsonRpcDescriptor CreateServerServiceDescriptor(string serv /// /// Descriptor for services proferred by the debugger server (implemented in C#). /// - public static ServiceJsonRpcDescriptor CreateDebuggerServiceDescriptor(string serviceName, Version? version = null) - => CreateDescriptor(CreateMoniker(VisualStudioComponentNamespace, DebuggerComponentName, serviceName, version)); + public static ServiceJsonRpcDescriptor CreateDebuggerServiceDescriptor(string serviceName, Version? version = null, MultiplexingStream.Options? streamOptions = null) + => CreateDescriptor(CreateMoniker(VisualStudioComponentNamespace, DebuggerComponentName, serviceName, version), streamOptions); /// /// Descriptor for services proferred by the debugger server (implemented in TypeScript). @@ -116,7 +120,11 @@ public static ServiceJsonRpcDescriptor CreateMauiServiceDescriptor(string servic new MultiplexingStream.Options { ProtocolMajorVersion = 3 }) .WithExceptionStrategy(ExceptionProcessing.ISerializable); - private static ServiceJsonRpcDescriptor CreateDescriptor(ServiceMoniker moniker) - => new ServiceJsonRpcDescriptor(moniker, Formatters.MessagePack, MessageDelimiters.BigEndianInt32LengthHeader) - .WithExceptionStrategy(ExceptionProcessing.ISerializable); + private static ServiceJsonRpcDescriptor CreateDescriptor(ServiceMoniker moniker, MultiplexingStream.Options? streamOptions = null) + { + var descriptor = streamOptions is not null + ? new ServiceJsonRpcDescriptor(moniker, clientInterface: null, Formatters.MessagePack, MessageDelimiters.BigEndianInt32LengthHeader, streamOptions) + : new ServiceJsonRpcDescriptor(moniker, Formatters.MessagePack, MessageDelimiters.BigEndianInt32LengthHeader); + return descriptor.WithExceptionStrategy(ExceptionProcessing.ISerializable); + } } diff --git a/src/Workspaces/Remote/Core/EditAndContinue/ManagedHotReloadLanguageService.cs b/src/Workspaces/Remote/Core/EditAndContinue/ManagedHotReloadLanguageService.cs index fd9f0817345e9..b3bc1cd42fbe9 100644 --- a/src/Workspaces/Remote/Core/EditAndContinue/ManagedHotReloadLanguageService.cs +++ b/src/Workspaces/Remote/Core/EditAndContinue/ManagedHotReloadLanguageService.cs @@ -250,19 +250,11 @@ public async ValueTask GetUpdatesAsync(CancellationToke var designTimeSolution = await GetCurrentDesignTimeSolutionAsync(cancellationToken).ConfigureAwait(false); var solution = GetCurrentCompileTimeSolution(designTimeSolution); - ModuleUpdates moduleUpdates; - ImmutableArray diagnosticData; - ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> rudeEdits; - DiagnosticData? syntaxError; + EmitSolutionUpdateResults.Data results; try { - var results = await encService.EmitSolutionUpdateAsync(_debuggingSession.Value, solution, s_emptyActiveStatementProvider, cancellationToken).ConfigureAwait(false); - - moduleUpdates = results.ModuleUpdates; - diagnosticData = results.Diagnostics.ToDiagnosticData(solution); - rudeEdits = results.RudeEdits; - syntaxError = results.GetSyntaxErrorData(solution); + results = (await encService.EmitSolutionUpdateAsync(_debuggingSession.Value, solution, s_emptyActiveStatementProvider, cancellationToken).ConfigureAwait(false)).Dehydrate(); } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { @@ -273,20 +265,22 @@ public async ValueTask GetUpdatesAsync(CancellationToke Location.None, string.Format(descriptor.MessageFormat.ToString(), "", e.Message)); - diagnosticData = [DiagnosticData.Create(designTimeSolution, diagnostic, project: null)]; - rudeEdits = []; - moduleUpdates = new ModuleUpdates(ModuleUpdateStatus.RestartRequired, []); - syntaxError = null; + results = new EmitSolutionUpdateResults.Data() + { + Diagnostics = [DiagnosticData.Create(designTimeSolution, diagnostic, project: null)], + RudeEdits = [], + ModuleUpdates = new ModuleUpdates(ModuleUpdateStatus.RestartRequired, []), + SyntaxError = null + }; } // Only store the solution if we have any changes to apply, otherwise CommitUpdatesAsync/DiscardUpdatesAsync won't be called. - if (moduleUpdates.Status == ModuleUpdateStatus.Ready) + if (results.ModuleUpdates.Status == ModuleUpdateStatus.Ready) { _pendingUpdatedDesignTimeSolution = designTimeSolution; } - var diagnostics = await EmitSolutionUpdateResults.GetAllDiagnosticsAsync(solution, diagnosticData, rudeEdits, syntaxError, moduleUpdates.Status, cancellationToken).ConfigureAwait(false); - return new ManagedHotReloadUpdates(moduleUpdates.Updates, diagnostics); + return new ManagedHotReloadUpdates(results.ModuleUpdates.Updates, results.GetAllDiagnostics()); } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { diff --git a/src/Workspaces/Remote/Core/RemoteWorkspacesResources.resx b/src/Workspaces/Remote/Core/RemoteWorkspacesResources.resx index fd418d75e0cfb..b95710fff4a67 100644 --- a/src/Workspaces/Remote/Core/RemoteWorkspacesResources.resx +++ b/src/Workspaces/Remote/Core/RemoteWorkspacesResources.resx @@ -231,4 +231,7 @@ Semantic search + + Related documents + \ No newline at end of file diff --git a/src/Workspaces/Remote/Core/ServiceDescriptors.cs b/src/Workspaces/Remote/Core/ServiceDescriptors.cs index cc577e5aecbef..f60effa5d1b62 100644 --- a/src/Workspaces/Remote/Core/ServiceDescriptors.cs +++ b/src/Workspaces/Remote/Core/ServiceDescriptors.cs @@ -25,6 +25,7 @@ using Microsoft.CodeAnalysis.LegacySolutionEvents; using Microsoft.CodeAnalysis.NavigateTo; using Microsoft.CodeAnalysis.NavigationBar; +using Microsoft.CodeAnalysis.RelatedDocuments; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.SemanticSearch; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -74,6 +75,7 @@ internal sealed class ServiceDescriptors (typeof(IRemoteNavigateToSearchService), typeof(IRemoteNavigateToSearchService.ICallback)), (typeof(IRemoteNavigationBarItemService), null), (typeof(IRemoteProcessTelemetryService), null), + (typeof(IRemoteRelatedDocumentsService), typeof(IRemoteRelatedDocumentsService.ICallback)), (typeof(IRemoteRenamerService), null), (typeof(IRemoteSemanticClassificationService), null), (typeof(IRemoteSemanticSearchService), typeof(IRemoteSemanticSearchService.ICallback)), diff --git a/src/Workspaces/Remote/Core/ServiceHubRemoteHostClient.cs b/src/Workspaces/Remote/Core/ServiceHubRemoteHostClient.cs index 8060625ad45c5..a53a2fbb69349 100644 --- a/src/Workspaces/Remote/Core/ServiceHubRemoteHostClient.cs +++ b/src/Workspaces/Remote/Core/ServiceHubRemoteHostClient.cs @@ -4,24 +4,15 @@ using System; using System.Diagnostics; -using System.Globalization; -using System.IO; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Extensions; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Telemetry; using Microsoft.ServiceHub.Client; using Microsoft.ServiceHub.Framework; -using Microsoft.VisualStudio.Threading; -using Roslyn.Utilities; -using StreamJsonRpc; namespace Microsoft.CodeAnalysis.Remote { diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf index 1952a68d6107c..90c06c2b86709 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf @@ -117,6 +117,11 @@ Shromažďování telemetrie projektu + + Related documents + Related documents + + Rename Přejmenovat diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf index fd93b541870a3..f1c31c329fc9e 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf @@ -117,6 +117,11 @@ Projekttelemetriesammlung + + Related documents + Related documents + + Rename Umbenennen diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf index a44445bf246f5..f889e492ff8ef 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf @@ -117,6 +117,11 @@ Recopilación de telemetría del proyecto + + Related documents + Related documents + + Rename Cambiar nombre diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf index 5716eac1da72d..1b7eb01b22b22 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf @@ -117,6 +117,11 @@ Collecte de la télémétrie du projet + + Related documents + Related documents + + Rename Renommer diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf index da0a370f45582..0d2e18bd2629f 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf @@ -117,6 +117,11 @@ Raccolta dei dati di telemetria del progetto + + Related documents + Related documents + + Rename Rinomina diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf index 5e5dd28599443..47d7c0260521d 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf @@ -117,6 +117,11 @@ プロジェクト テレメトリ コレクション + + Related documents + Related documents + + Rename 名前の変更 diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf index 237b0f35d3959..c0aa533c77258 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf @@ -117,6 +117,11 @@ 프로젝트 원격 분석 컬렉션 + + Related documents + Related documents + + Rename 이름 바꾸기 diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf index 0f3c74e8aa0a0..f78f3df256631 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf @@ -117,6 +117,11 @@ Kolekcja telemetrii projektu + + Related documents + Related documents + + Rename Zmień nazwę diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf index 2acd0f066e1a3..41321490c4d63 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf @@ -117,6 +117,11 @@ Coleção de telemetria do projeto + + Related documents + Related documents + + Rename Renomear diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf index 1ff21f5a6cdf0..71a1ea99d6728 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf @@ -117,6 +117,11 @@ Сбор данных телеметрии проекта + + Related documents + Related documents + + Rename Переименовать diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf index a29596410f964..02cc65e31deda 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf @@ -117,6 +117,11 @@ Proje telemetri koleksiyonu + + Related documents + Related documents + + Rename Yeniden adlandır diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf index 73b29cbdbb4ee..7e6c1e9335b94 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf @@ -117,6 +117,11 @@ 项目遥测集合 + + Related documents + Related documents + + Rename 重命名 diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf index 589380d9a042b..06ca8721713d0 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf @@ -117,6 +117,11 @@ 專案遙測集合 + + Related documents + Related documents + + Rename 重新命名 diff --git a/src/Workspaces/Remote/ServiceHub.CoreComponents/CoreComponents.Shared.targets b/src/Workspaces/Remote/ServiceHub.CoreComponents/CoreComponents.Shared.targets index 8ce2d5ff4c0e0..0bd122d3d7a83 100644 --- a/src/Workspaces/Remote/ServiceHub.CoreComponents/CoreComponents.Shared.targets +++ b/src/Workspaces/Remote/ServiceHub.CoreComponents/CoreComponents.Shared.targets @@ -35,9 +35,12 @@ --> - - + + + <_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..c8ebe898b6369 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/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/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/xlf/CSharpCompilerExtensionsResources.cs.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf index fa634e3a893ac..3d79ebedea941 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}' + EditorConfig option '{0}' contains unrecognized value '{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..0139f745a0252 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}' + EditorConfig option '{0}' contains unrecognized value '{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..1abe399f3b702 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}' + EditorConfig option '{0}' contains unrecognized value '{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..e1130a8d9c16c 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}' + EditorConfig option '{0}' contains unrecognized value '{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..2cf575979d03d 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}' + EditorConfig option '{0}' contains unrecognized value '{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..e8e4570cf8558 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 option '{0}' contains unrecognized value '{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..b46ec8225cfd4 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 option '{0}' contains unrecognized value '{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..6df6602b8d1a9 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}' + EditorConfig option '{0}' contains unrecognized value '{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..df79eee5eba50 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}' + EditorConfig option '{0}' contains unrecognized value '{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..35404bbfb4ccf 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 option '{0}' contains unrecognized value '{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..764f455d11999 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}' + EditorConfig option '{0}' contains unrecognized value '{1}' + + 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..796f60339e21c 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 option '{0}' contains unrecognized value '{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..c503de3b330f6 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 option '{0}' contains unrecognized value '{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/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index c00a31249fe65..3c9d6c4f2a066 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -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/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/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 100% rename from src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.AnonymousTypeRemover.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.AnonymousTypeRemover.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs similarity index 100% rename from src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.UnavailableTypeParameterRemover.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.UnavailableTypeParameterRemover.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.UnavailableTypeParameterRemover.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.UnavailableTypeParameterRemover.cs diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.UnnamedErrorTypeRemover.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.UnnamedErrorTypeRemover.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.UnnamedErrorTypeRemover.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.UnnamedErrorTypeRemover.cs 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/Formatting/Context/FormattingContext.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.cs index c8b089dba4893..2bc8ff306e9c6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.cs @@ -24,7 +24,6 @@ namespace Microsoft.CodeAnalysis.Formatting; internal 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/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/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/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/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/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/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/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/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/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/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/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/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.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..42108cfaf4036 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AbstractSpeculationAnalyzer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AbstractSpeculationAnalyzer.cs @@ -42,10 +42,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 +53,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 +80,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; @@ -100,7 +99,7 @@ public AbstractSpeculationAnalyzer( /// /// Original expression to be replaced. /// - public TExpressionSyntax OriginalExpression => _expression; + public TExpressionSyntax OriginalExpression { get; } SyntaxNode ISpeculationAnalyzer.OriginalExpression => OriginalExpression; @@ -126,7 +125,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,7 +169,7 @@ public SemanticModel SpeculativeSemanticModel } } - public CancellationToken CancellationToken => _cancellationToken; + public CancellationToken CancellationToken { get; } protected abstract SyntaxNode GetSemanticRootForSpeculation(TExpressionSyntax expression); @@ -205,7 +204,7 @@ 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); } } @@ -406,6 +405,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 +455,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 && @@ -650,7 +660,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; @@ -751,16 +761,16 @@ private bool ReplacementBreaksForEachStatement(TForEachStatementSyntax forEachSt { var forEachExpression = GetForEachStatementExpression(forEachStatement); if (forEachExpression.IsMissing || - !forEachExpression.Span.Contains(_expression.SpanStart)) + !forEachExpression.Span.Contains(OriginalExpression.SpanStart)) { return false; } // 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); + var local = (ILocalSymbol)OriginalSemanticModel.GetRequiredDeclaredSymbol(forEachStatement, CancellationToken); + var newLocal = (ILocalSymbol)this.SpeculativeSemanticModel.GetRequiredDeclaredSymbol(newForEachStatement, CancellationToken); if (!SymbolsAreCompatible(local.Type, newLocal.Type)) { return true; @@ -804,7 +814,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); @@ -847,7 +857,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 { @@ -875,7 +885,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; 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/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/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/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/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/SymbolEquivalenceComparer.EquivalenceVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs index 64c2f3e0110d5..7cd4731cd37ac 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; @@ -13,23 +14,17 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; internal 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..bff84030a7c8b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.GetHashCodeVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.GetHashCodeVisitor.cs @@ -13,22 +13,19 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; internal 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.SignatureTypeSymbolEquivalenceComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.SignatureTypeSymbolEquivalenceComparer.cs index 1f533427ebda7..ebe047cf61e5d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.SignatureTypeSymbolEquivalenceComparer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.SignatureTypeSymbolEquivalenceComparer.cs @@ -8,15 +8,15 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; internal 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..55c35b8f91a84 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(). + Instantiated part(s) threw exception(s) from 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..b54658f83960d 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(). + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + + 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..dcb05e0f5bb20 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(). + Instantiated part(s) threw exception(s) from 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..3f1d586ad75cf 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(). + Instantiated part(s) threw exception(s) from 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..a17b3700cc77c 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(). + Instantiated part(s) threw exception(s) from 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..bb01d1d0469d4 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(). + Instantiated part(s) threw exception(s) from 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..ae836a31c9d0e 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(). + Instantiated part(s) threw exception(s) from 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..575e32d992333 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(). + Instantiated part(s) threw exception(s) from 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..6fcf0e1488c56 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(). + Instantiated part(s) threw exception(s) from 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..d126d85660729 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(). + Instantiated part(s) threw exception(s) from 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..26e149d566fbe 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(). + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + + 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..b930f0d15338d 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(). + Instantiated part(s) threw exception(s) from 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..d3685d1ee9637 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(). + Instantiated part(s) threw exception(s) from 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/Workspace/CSharp/CSharpWorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems index f2cba6f9d9789..9ae36e4cfee9e 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 @@ + + @@ -53,6 +55,7 @@ + @@ -87,6 +90,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/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 dcadf01561c48..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/CodeActionOptions.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Runtime.Serialization; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; -using Microsoft.CodeAnalysis.Host; -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; -#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/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/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/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 92% rename from src/Features/Core/Portable/Options/MemberDisplayOptions.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Options/MemberDisplayOptions.cs index 67bb9061167d2..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,7 +25,7 @@ internal readonly record struct MemberDisplayOptions() /// internal static class MemberDisplayOptionsStorage { - public static readonly OptionGroup TypeMemberGroup = new(name: "type_members", description: FeaturesResources.Type_members, priority: 3, parent: null); + 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/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 100% rename from src/Workspaces/Core/Portable/Simplification/Simplifiers/AbstractSimplifier.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/Simplifiers/AbstractSimplifier.cs 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/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/xlf/WorkspaceExtensionsResources.cs.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.cs.xlf index fbabe19a86657..a60da48a55a68 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 + Document does not support syntax trees + + Fix all '{0}' Opravit vše ({0}) @@ -122,6 +127,11 @@ Řešení neobsahuje zadaný dokument. + + Type members + Type members + + 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..995b68f6cdc1e 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 + Document does not support syntax trees + + Fix all '{0}' Alle '{0}' reparieren @@ -122,6 +127,11 @@ Die Lösung enthält nicht das angegebene Dokument. + + Type members + Type members + + 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..e6745b37d88fc 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 + Document does not support syntax trees + + Fix all '{0}' Corregir todo '{0}' @@ -122,6 +127,11 @@ La solución no contiene el documento especificado. + + Type members + Type members + + 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..77410516acc7e 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 + Document does not support syntax trees + + Fix all '{0}' Corriger tous les '{0}' @@ -122,6 +127,11 @@ La solution ne contient pas le document spécifié. + + Type members + Type members + + 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..8a61e31916cc2 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 + Document does not support syntax trees + + Fix all '{0}' Correggi tutti '{0}' @@ -122,6 +127,11 @@ La soluzione non contiene il documento specificato. + + Type members + Type members + + 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..3ab1c061fa6e0 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 + Document does not support syntax trees + + Fix all '{0}' すべての '{0}' を修正します @@ -122,6 +127,11 @@ ソリューションには、指定されたドキュメントがありません。 + + Type members + 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..743ddc1427d63 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 + Document does not support syntax trees + + Fix all '{0}' 모든 '{0}' 수정 @@ -122,6 +127,11 @@ 솔루션에 지정한 문서가 포함되어 있지 않습니다. + + Type members + 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..d623e8539d6b5 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 + Document does not support syntax trees + + Fix all '{0}' Napraw wszystkie wystąpienia elementu „{0}” @@ -122,6 +127,11 @@ Rozwiązanie nie zawiera określonego dokumentu. + + Type members + Type members + + 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..45b3ab8edfc19 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 + Document does not support syntax trees + + Fix all '{0}' Corrigir todos os '{0}' @@ -122,6 +127,11 @@ A solução não contém o documento especificado. + + Type members + Type members + + 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..d70e6f24275d0 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 + Document does not support syntax trees + + Fix all '{0}' Исправить все "{0}" @@ -122,6 +127,11 @@ Указанный документ отсутствует в решении. + + Type members + 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..9f1c59f4f1e32 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 + Document does not support syntax trees + + Fix all '{0}' Geçtiği her yerde '{0}' ifadesini düzelt @@ -122,6 +127,11 @@ Çözüm belirtilen belgeyi içermiyor. + + Type members + Type members + + 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..9592fe49841f7 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 + Document does not support syntax trees + + Fix all '{0}' 修复所有“{0}” @@ -122,6 +127,11 @@ 解决方案不包含指定的文档。 + + Type members + 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..1deadfe4feb24 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 + Document does not support syntax trees + + Fix all '{0}' 修正所有 '{0}' @@ -122,6 +127,11 @@ 此方案不包含指定的文件。 + + Type members + 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)